3
\$\begingroup\$

I require that the Feature set of my Licence to have a non-empty intersection with a set of features that the module I am loading contains. I expect other lists in my License to form similar requirements, and I wish to be able to specify as much information as possible on the license object, i.e. I do not wish to need to update the Validator if the contents of the License object changes.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;
namespace Testing
{
 public class License
 {
 [CollectionIntersects]
 public List<string> Features { get; set; } 
 }
 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
 public abstract class LicenseValidator:Attribute
 {
 public abstract bool isValid(object context, object obj, PropertyInfo property);
 }
 public class Validator
 {
 public static bool isValid(object context, object obj)
 {
 bool valid = true;
 Type objType = obj.GetType();
 PropertyInfo[] props = objType.GetProperties();
 foreach (PropertyInfo prop in props)
 {
 foreach (LicenseValidator validator in prop.GetCustomAttributes<LicenseValidator>())
 {
 valid=valid&&validator.isValid(context, obj, prop);
 }
 }
 return valid;
 }
 }
 public class CollectionIntersects: LicenseValidator
 {
 public CollectionIntersects()
 {
 }
 public override bool isValid(object context, object obj, PropertyInfo property)
 {
 Type collectionType = property.PropertyType;
 Object contextvalue = property.GetValue(context);
 Object objectvalue = property.GetValue(obj);
 //Casting code lifted from
 //http://stackoverflow.com/a/31380177/1986513.
 var param = Expression.Parameter(typeof(object));
 dynamic contextvalueenum =
 Expression.Lambda(Expression.Convert(param, collectionType), param).Compile().DynamicInvoke(contextvalue);
 dynamic licencevalueenum =
 Expression.Lambda(Expression.Convert(param, collectionType), param).Compile().DynamicInvoke(objectvalue);
 return ((IEnumerable<object>)Enumerable.Intersect(contextvalueenum, licencevalueenum)).Any();
 }
 }
}

Is there an easier way to accomplish this? Also, how sensitive is it to localization and collation issues considering that the license might be written in a different locale than the reference context object?

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Mar 3, 2016 at 16:03
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Self answer, one nights sleep later.

A simpler solution can be made by making the arguments of the function dynamic. The isValid method can then be written as;

 public override bool isValid(dynamic context, dynamic obj, PropertyInfo property)
 {
 return ((IEnumerable<object>)Enumerable.Intersect(property.GetValue(context), property.GetValue(obj))).Any();
 }
answered Mar 4, 2016 at 12:44
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.