我正在尝试创建一种通用的方式来保存应针对给定类搜索的属性。
我创建了以下结构来保存此信息:
public struct Lookup<T> where T: BaseEntity
{
public Expression<Func<T, object>> Parent { get; set; }
}
然后创建了一个字典,如下所示:
readonly Dictionary<string, Lookup<BaseEntity>> _dict =
new Dictionary<string, Lookup<BaseEntity>>();
我有一个使用
BaseEntity
作为基类的类:public class Agency : BaseEntity
{
public int AgencyId { get; set; }
}
我使用以下信息创建一个新的Lookup结构:
new Lookup<Agency>
{
Parent = x => x.Id
};
但是,如果我尝试将其添加到字典中,则会出现以下错误:
Cannot convert from Lookup<Agency> to Lookup<BaseEntity>
我本来以为这是可行的,因为它们属于相同的基本类型,这是怎么回事。
我要添加许多实体,因此希望能通用地进行,而不必进行if / switch等操作。
谢谢
最佳答案
不,Lookup<BaseEntity>
不是Lookup<Agency>
的基本类型。 Agency
源自BaseEntity
的事实还不够。但是首先,让我们看看其他的东西。
考虑一下通常的方差规则。您的方法对应于
object DoSomething(T x) { ... }
现在,在
Lookup<BaseEntity>
中,object DoSomething(BaseEntity x) { ... }
到目前为止,一切都很好-通过
Agency
代替BaseEntity
是完全合法的,因为Agency
源自BaseEntity
。但是,事实并非如此。您创建了这个:object DoSomething(Agency x) { ... }
显然,您不能传递
BaseEntity
而不是Agency
-这将完全破坏键入。与Java不同,C#(和.NET通常)的泛型在编译时和运行时都是真实的,它们不会退回到Lookup<BaseEntity>
。此外,C#/。NET限制了方差的使用。您可以在简单的表达式和委托中免费获得差异,但不能在类或泛型类中获得差异。您需要明确说明所需的差异类型,并使用接口。例如,您的情况是这样的:
public interface ILookup<out T>
这将允许您执行从
ILookup<Agency>
到ILookup<BaseEntity>
的转换。但是,这对于您的情况是不够的,因为T
在您的情况下既是协变的又是协变的-换句话说,您不能朝任一方向进行转换。但是,这没什么大不了的,因为您使事情变得有些复杂。虽然您需要强类型来创建
Lookup<Agency>
,但您并不需要类型本身-无论如何,您都将使用未键入的Expression
:public sealed class Lookup
{
private readonly Expression parent;
private Lookup(Expression parent)
{
this.parent = parent;
}
public Expression Parent { get { return parent; } }
public static Lookup For<T>(Expression<Func<T, object>> member)
where T : BaseEntity
{
return new Lookup(member);
}
}
关于c# - 用子类创建泛型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38607983/