实例化具有泛型 属性 的泛型接口

Instantiate generic interface that has generic property

我正在尝试重构一个非常具体的代码以使其更通用,这样我们就可以扩展用例,但我在处理通用类型时遇到了困难。有问题的代码是(只需添加签名和我需要帮助的部分):

public class Data { }

public class PersonData : Data { }

public interface IDataSchema<T> where T : Data { }

public class PersonEntityProvider
{
    public IDataSchema<PersonData> PersonSchema { get; }
}

public class EntityManager
{
    private PersonEntityProvider personEntityProvider;

    public PersonEntityProvider PersonEntityProvider => personEntityProvider = new PersonEntityProvider();
}

我真正想做的是通过工厂模式让 EntityManager class 接受多个 EntityProvidersEntityProviders 需要一个由 IDataSchema 定义的架构,该架构使用表示数据的基础 class。

所以我试图做的是让 EntityManager 依赖于 EntityProviders 的抽象:

public interface IEntityProvider<T> where T : Data
{
    IDataSchema<T> DataSchema { get; }
}

public class PersonEntityProvider : IEntityProvider<PersonData>
{
    public IDataSchema<PersonData> DataSchema { get; }
}

public class EntityManager
{
    private IEntityProvider<Data> entityProvider;

    public IEntityProvider<Data> EntityProvider =>
        entityProvider = new PersonEntityProvider();
}

但是当我尝试实例化提供程序时,编译器告诉我无法将 PersonEntityProvider 转换为 IEntityProvider<Data>。我认为它会起作用,因为 PersonData 是从数据派生的,但显然不起作用。我也想过让 EntityManager 通用,但这需要对我现在不想触及的部分进行太多更改...所以我尝试更改界面以使其不是通用的:

public interface IEntityProvider
{
    IDataSchema<Data> DataSchema { get; }
}

public class PersonEntityProvider : IEntityProvider
{
    public IDataSchema<PersonData> DataSchema { get; }
}

public class EntityManager
{
    private IEntityProvider entityProvider;

    public IEntityProvider EntityProvider => entityProvider = new PersonEntityProvider();
}

也不行,这次它告诉我我的PersonEntityProvider不遵循接口约定,因为IDataSchema的类型需要是Data,而不是PersonData.

我觉得我错过了什么,但我坚持了几个小时。你怎么看?

您或许可以将 IDataSchemaIEntityProvider 接口的类型参数设置为 covariant (in essence, the same way IEnumerable<T>声明):

public interface IDataSchema<out T>  where T : Data {}

public interface IEntityProvider<out T> where T : Data
{
    IDataSchema<T> DataSchema { get; }
}

(注意注释泛型类型参数的 out 关键字。)

然而,使用协变类型参数会对接口产生一些限制:

  • 作为协变泛型类型参数类型的属性不能具有由接口声明的 setter。
  • 接口声明的方法的参数不能使用协变泛型类型参数(方法的return类型仍然可以是协变泛型类型参数)。

尽管 PersonData 继承自 Data,但当它们被使用时 Data 并不是 PersonalData 它们共享属性,因为其中一个是继承者。

这是你的问题:

public class EntityManager
{
    private IEntityProvider<Data> entityProvider;

    public IEntityProvider<Data> EntityProvider =>
        entityProvider = new PersonEntityProvider();
}

在这里,您的 entityProviderEntityProvider 方法属于 IEntityProvider<Data> 类型,而不是 IEntityProvider<PersonData>...所以问题在于转换。


解决方法


public interface IData { }

public class Data : IData { }

public class PersonData : Data { }

public interface IDataSchema<T> where T : IData { }

public interface IEntityProvider<T> where T : IData
{
    IDataSchema<T> DataSchema { get; }
}

public class PersonEntityProvider : IEntityProvider<IData>
{
    public IDataSchema<IData> DataSchema { get; }
}

public class EntityManager
{
    private IEntityProvider<IData> entityProvider;

    public IEntityProvider<IData> EntityProvider =>
        entityProvider = new PersonEntityProvider();
}

在这里,您声明了一个新接口 IDataData 实现了该接口。那么,PersonData继承自Data。请记住,为确保事物是通用的,将类型保留为接口而不是 类 ...就像您在问题中使用 Data 作为定义类型一样。因此,您可以在任何有 PersonDataData 类 的地方使用 IData 作为 return 类型,就像您在我建议的代码中看到的那样。我在 VS 上检查了我建议的代码,它有效。