Приведение функции доступа к члену из Func‹DerivedFromT,object› в Func‹T,object›

Я пытаюсь создать динамическое базовое сопоставление с помощью свободного nhibernate.

Я проверяю BaseMap‹ T > : ClassMap‹ T > если, например: (typeof(ICategorizedEntity).IsAssignableFrom(typeof(T)))

Если это так, я хочу сопоставить свойство с именем «Категория», которое принадлежит интерфейсу ICategorizedEntity, но функция Map(Func) принимает только свойства T, поэтому я попытался немного угадать с linq и придумал это:

   Expression<Func<ICategorizedEntity, object>> exp = x => x.Category;
   var parameter = Expression.Parameter(typeof (T));
   var lmd = Expression.Lambda<Func<T, object>>(exp, parameter);
   Map(lmd);

Что не работает, потому что глубоко внутри функции «Карта» проверяется следующее:

   MemberExpression memberExpression = (MemberExpression) null;
   if (expression.NodeType == ExpressionType.Convert)
       memberExpression = ((UnaryExpression) expression).Operand as MemberExpression;
   else if (expression.NodeType == ExpressionType.MemberAccess)
       memberExpression = expression as MemberExpression;
   if (enforceCheck && memberExpression == null)
       throw new ArgumentException("Not a member access", "expression");

И я получаю «Не доступ к члену\r\nИмя параметра: выражение».

Как я могу создать и применить MemberExpression или что-то подобное, что будет работать?


person Adam Tal    schedule 10.02.2012    source источник


Ответы (2)


Func<DerivedFromT,object> представляет собой метод, который принимает параметр DerivedFromT. Func<T,object> представляет собой метод, который принимает параметр T. С помощью расхождения делегирования, представленного в C# 4, вы можете преобразовать Func<T,object> в Func<DerivedFromT,object>, но не наоборот (как вы просите).

Подумайте, что это значит:

public class Person { }

public class Student : Person { }

public static class School
{
    public static object Greet(Person person)
    {
        return null; 
    }

    public static object Promote(Student student)
    { 
        return null; 
    }
}

В этом случае метод Greet соответствует делегату Func<Person,object>, а метод Promote соответствует делегату Func<Student,object>.

Func<Person, object> greetPerson = School.Greet;
Func<Student, object> promoteStudent = School.Promote;

Мы можем преобразовать Greet в Func<Student,object>; если мы можем поприветствовать Person, то мы также можем поприветствовать Student (который гарантированно является специализированной формой Person).

Func<Student, object> greetStudent = greetPerson;

Однако мы не можем преобразовать Promote в Func<Person,object>; хотя мы можем продвигать Student, мы не можем продвигать вообще Person, если только он/она не является Student.

Func<Person, object> promotePerson = promoteStudent;   // Will not compile.

Если мы знаем, что наш Person является студентом, мы можем указать это, приведя его:

Func<Person, object> promotePerson =
    personWhoIsActuallyStudent => promoteStudent((Student)personWhoIsActuallyStudent);
person Douglas    schedule 10.02.2012
comment
Спасибо за хорошее объяснение, Дуглас, но я думаю, вы неправильно поняли, чего я пытался добиться. Старое доброе преобразование помогло: Map(x =› ((ICategorizedEntity)x).Category); - person Adam Tal; 11.02.2012
comment
Признаюсь, я действительно не понял вашего вопроса, поэтому мой пост был основан в основном на вашем заголовке. Однако я предположил, что ответ, вероятно, будет лежать в моей последней строке кода, которая выполняет требуемое приведение лямбда. - person Douglas; 11.02.2012

Спасибо, Дуглас, вы привели меня к правильному (простому) ответу.

Я зашел слишком далеко, пытаясь найти его..

Старое доброе преобразование (внутри лямбда-выражения) помогло:

   Map(x => ((ICategorizedEntity)x).Category);
person Adam Tal    schedule 11.02.2012