我正在尝试创建一种通用方法来保存我应该在给定类时搜索的属性。
我创建了以下结构来保存这些信息:
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等。
由于
答案 0 :(得分:3)
不,Agency
不是BaseEntity
的基本类型。 object DoSomething(T x) { ... }
派生自Lookup<BaseEntity>
这一事实并不充分。但首先,让我们看看别的东西。
考虑通常的差异规则。您的方法对应
object DoSomething(BaseEntity x) { ... }
现在,在Agency
中,这变为
BaseEntity
到目前为止,非常好 - 通过Agency
代替BaseEntity
完全合法,因为object DoSomething(Agency x) { ... }
来自BaseEntity
。但是,你的情况并非如此。你创建了这个:
Agency
显然,您无法通过Lookup<BaseEntity>
代替public interface ILookup<out T>
- 这会完全打破输入。与Java不同,C#(以及一般的.NET)泛型在编译时和运行时都是真实的,它们不会回退到ILookup<Agency>
。
此外,C#/ .NET限制了方差的使用。您可以在简单表达式和委托中免费获得差异,但不能在类或泛型类中获得。您需要明确您想要的方差类型,并使用接口。例如,在您的情况下,您可能会遇到以下情况:
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);
}
}
,但您在类型本身中并不需要它 - 您无论如何都将使用无类型的{{1}}:
{{1}}