views:

308

answers:

2

I am trying to develop some general purpose custom ValidationAttributes. The fact that one cannot create a generic subclass of an attribute is making me nuts.

Here is my code for the IsValid override in a ValidationAttribute to verify that the value of a property is unique:

    public override bool IsValid(object value)
    {
        SomeDataContext context = SomeDataContext.GetNewDataContext();
        Type tableType = typeof(Table<>).MakeGenericType(new Type[] { _EntityType });
        var table = Activator.CreateInstance(tableType);
        //ITable table = context.GetTable(_EntityType);
        var codeProp = (from member in context.Mapping.GetMetaType(_EntityType).DataMembers
                        where member.Name == _PropertyName
                        select member.Member).Single();
        ParameterExpression param = Expression.Parameter(_EntityType, "x");
        MemberExpression memberExp = Expression.Property(param, (PropertyInfo)codeProp); 
        Expression body = Expression.Equal(memberExp, Expression.Constant(value, typeof(char)));
        //var predicate = Expression.Lambda<Func<TEntityType, bool>>(body, param);
        Type lambdaType = typeof(Func<,>).MakeGenericType(_EntityType, typeof(bool));
        var predicate = Expression.Lambda(lambdaType, body, param);
        object code = table.FirstOrDefault(predicate);
        if (code != null)
        {
            return false;
        }
        return true;
    }

This line:

object code = table.FirstOrDefault(predicate);

errors out:

'object' does not contain a definition for 'FirstOrDefault' and no extension ......etc.

How do I define, cast or otherwise get the compiler to recognize "table" as something that exposes a .FirstOrDefault method?

Thanks

+2  A: 

How do I define, cast or otherwise get the compiler to recognize "table" as something that exposes a .FirstOrDefault method?

By using an explicit cast to IEnumerable<> of something. Since you don't know the “something” in your case, you effectively cannot use FirstOrDefault. Simply implement the logic yourself:

var enumerator = ((IEnumerable)table).GetEnumerator();
object code = enumerator.MoveNext() ? enumerator.Value : null;
Konrad Rudolph
I don't think this helps me as I am creating an expression tree linq2sql will use to build an SQL statement.
theBruce
+2  A: 

This will get you to a type that System.Linq.Enumerable can use:

IEnumerable<object> tableGeneric =
  ((IEnumerable)table).OfType<object>();

Three concerns:

  1. Don't use var so much - you'll lose track of your types.
  2. I'm unsure about using your predicate in a FirstOrDefault call - I don't see how the compiler can type check it. http://msdn.microsoft.com/en-us/library/bb299425.aspx
  3. If you get the predicate working, .Any() might be a better choice than .FirstOrDefault()
David B