将成员访问函数从“Func<DerivedFromT, object>”转换为“Func<T, object>”。

3
我正在尝试使用Fluent NHibernate创建动态基础映射。我的做法是在BaseMap<T>:ClassMap<T>中检查是否满足以下条件:(typeof(ICategorizedEntity).IsAssignableFrom(typeof(T)))。如果是这样,我想映射一个名为“Category”的属性,该属性属于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);

这种方法不起作用,因为在“Map”函数内部它会检查以下内容:

   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参数名称:expression”的错误。

我应该如何创建和转换MemberExpression或任何类似的内容,以使其正常工作?

2个回答

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);

感谢您的详细解释,但我认为您误解了我的意图。老式转换方法解决了问题: Map(x => ((ICategorizedEntity)x).Category); - Adam Tal
我承认我真的不理解你的问题,所以我的帖子大多基于你的标题。然而,我假设答案可能在我的最后一行代码中,它执行了你所需的 lambda 强制转换。 - Douglas

2

谢谢Douglas,你带我找到了正确(简单)的答案。

我尝试了太多,结果偏离了方向。

在lambda表达式中进行良好的转换就解决了问题:

   Map(x => ((ICategorizedEntity)x).Category);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接