根据给定的类型实现泛型方法调用
Achieve generic method invocation depending on the type given
我有一些(非)通用函数明确分配给 DbSet
(使用 Entity Framework 6.1,但从某种意义上说,这个问题更通用):
//Non-generic type method
public static IQueryable BuildQuery(this DbSet dbSet)
{
return dbSet;
}
//Generic base class elements method
public static IQueryable<Entity> BuildQuery(this DbSet<Entity> dbSet)
{
return dbSet.Include(de1 => de1.NavigationPropertyBase);
}
//Derived class 1 elements method
public static IQueryable<DerivedEntity1> BuildQuery(this DbSet<DerivedEntity1> dbSet)
{
return dbSet.Include(de1 => de1.NavigationPropertyX);
}
//Derived class 2 elements method
public static IQueryable<DerivedEntity2> BuildQuery(this DbSet<DerivedEntity2> dbSet)
{
return dbSet.Include(de2 => de2.NavigationPropertyX).
Include(de2 => de2.NavigationPropertyY);
}
我知道虽然 DerivedEntity1
和 DerivedEntity2
扩展了 Entity
,但 Dbset<DerivedEntityX>
没有扩展 DbSet<Entity>
。
不过,我想做的是基于通用类型实现 late-binding 类行为。我想将泛型类型放入一个非泛型变量中,然后调用 BuildQuery
方法(可见,因为它在编译时存在于非泛型类型中):
//This compiles with no errors.
DbSet dbSetNonGeneric = dbSet; // dbSet is of DbSet<DerivedEntity1> type
var result = dbSetNonGeneric.BuildQuery();
我的问题是,这会导致根据泛型调用BuildQuery
方法还是会调用非泛型方法?而在第二种情况下,有没有办法实现那种方法调用?
will this lead to an invocation of the BuildQuery method according to the generic type or will it invoke the non-generic method?
它将使用非泛型重载。
And in the second case, is there a way to achieve that kind of method invocation?
您可以将变量键入 dynamic
,但结果也将是 dynamic
。
您也可以使用反射来确定 dbSetNonGeneric
的类型、您要使用的重载,并在对象上调用该重载。
更新:由于动态查找无法找到扩展方法 (link),因此应将这些方法用作普通静态方法,以便与 dynamic
.[=17= 结合使用]
它将调用非泛型方法。原因很简单,扩展方法调用基于变量类型而不是运行时类型(派生类型)
根据@Servy 的建议,您可以使用反射,但我对 dynamic
有疑问。
当您有扩展方法时,dynamic
关键字将不起作用。
要用反射调用,您必须做一些工作。实际上,当使用反射时,它不会成为实例方法的一部分,但它就像您用来创建扩展方法的静态 class 的静态方法。
以下link将帮助您获取该方法并使用反射进行调用。
Reflection to Identify Extension Methods
我有一些(非)通用函数明确分配给 DbSet
(使用 Entity Framework 6.1,但从某种意义上说,这个问题更通用):
//Non-generic type method
public static IQueryable BuildQuery(this DbSet dbSet)
{
return dbSet;
}
//Generic base class elements method
public static IQueryable<Entity> BuildQuery(this DbSet<Entity> dbSet)
{
return dbSet.Include(de1 => de1.NavigationPropertyBase);
}
//Derived class 1 elements method
public static IQueryable<DerivedEntity1> BuildQuery(this DbSet<DerivedEntity1> dbSet)
{
return dbSet.Include(de1 => de1.NavigationPropertyX);
}
//Derived class 2 elements method
public static IQueryable<DerivedEntity2> BuildQuery(this DbSet<DerivedEntity2> dbSet)
{
return dbSet.Include(de2 => de2.NavigationPropertyX).
Include(de2 => de2.NavigationPropertyY);
}
我知道虽然 DerivedEntity1
和 DerivedEntity2
扩展了 Entity
,但 Dbset<DerivedEntityX>
没有扩展 DbSet<Entity>
。
不过,我想做的是基于通用类型实现 late-binding 类行为。我想将泛型类型放入一个非泛型变量中,然后调用 BuildQuery
方法(可见,因为它在编译时存在于非泛型类型中):
//This compiles with no errors.
DbSet dbSetNonGeneric = dbSet; // dbSet is of DbSet<DerivedEntity1> type
var result = dbSetNonGeneric.BuildQuery();
我的问题是,这会导致根据泛型调用BuildQuery
方法还是会调用非泛型方法?而在第二种情况下,有没有办法实现那种方法调用?
will this lead to an invocation of the BuildQuery method according to the generic type or will it invoke the non-generic method?
它将使用非泛型重载。
And in the second case, is there a way to achieve that kind of method invocation?
您可以将变量键入 dynamic
,但结果也将是 dynamic
。
您也可以使用反射来确定 dbSetNonGeneric
的类型、您要使用的重载,并在对象上调用该重载。
更新:由于动态查找无法找到扩展方法 (link),因此应将这些方法用作普通静态方法,以便与 dynamic
.[=17= 结合使用]
它将调用非泛型方法。原因很简单,扩展方法调用基于变量类型而不是运行时类型(派生类型)
根据@Servy 的建议,您可以使用反射,但我对 dynamic
有疑问。
当您有扩展方法时,dynamic
关键字将不起作用。
要用反射调用,您必须做一些工作。实际上,当使用反射时,它不会成为实例方法的一部分,但它就像您用来创建扩展方法的静态 class 的静态方法。
以下link将帮助您获取该方法并使用反射进行调用。
Reflection to Identify Extension Methods