我正在尝试创建一种通用的方式来保存应针对给定类搜索的属性。

我创建了以下结构来保存此信息:

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/

10-10 05:55