实例化具有泛型 属性 的泛型接口
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 接受多个 EntityProviders
。 EntityProviders
需要一个由 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
.
我觉得我错过了什么,但我坚持了几个小时。你怎么看?
您或许可以将 IDataSchema 和 IEntityProvider 接口的类型参数设置为 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();
}
在这里,您的 entityProvider
和 EntityProvider
方法属于 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();
}
在这里,您声明了一个新接口 IData
,Data
实现了该接口。那么,PersonData
继承自Data
。请记住,为确保事物是通用的,将类型保留为接口而不是 类 ...就像您在问题中使用 Data
作为定义类型一样。因此,您可以在任何有 PersonData
或 Data
类 的地方使用 IData
作为 return 类型,就像您在我建议的代码中看到的那样。我在 VS 上检查了我建议的代码,它有效。
我正在尝试重构一个非常具体的代码以使其更通用,这样我们就可以扩展用例,但我在处理通用类型时遇到了困难。有问题的代码是(只需添加签名和我需要帮助的部分):
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 接受多个 EntityProviders
。 EntityProviders
需要一个由 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
.
我觉得我错过了什么,但我坚持了几个小时。你怎么看?
您或许可以将 IDataSchema
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();
}
在这里,您的 entityProvider
和 EntityProvider
方法属于 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();
}
在这里,您声明了一个新接口 IData
,Data
实现了该接口。那么,PersonData
继承自Data
。请记住,为确保事物是通用的,将类型保留为接口而不是 类 ...就像您在问题中使用 Data
作为定义类型一样。因此,您可以在任何有 PersonData
或 Data
类 的地方使用 IData
作为 return 类型,就像您在我建议的代码中看到的那样。我在 VS 上检查了我建议的代码,它有效。