是否可以声明一个泛型集合只保存实现任何<T>
的通用接口的对象?
我的问题归结为:如果我想/必须存储实现通用接口的对象,是否有比使用非泛型集合或(通用的<Object>
)更好的方式来表达该事实。
例:
// An example Generic Interface
interface ISyncInterface<T>
{
Task DoSync();
IEnumerable<T> NewItems { get; }
}
// a manager-class that registers different classes implementing
// the generic interface.
// The code works - can it be done better?
class Manager
{
private List<Object> _services = new List<Object>(); // <- works but is basically non generic
// however the RegisterService() ensures that only correct types can be added.
// would like to have something like below to indicate the Interface-Type
// however: this would only allow _services2.Add to hold types of ISyncInterface<Object>
// - ISyncInterface<ServiceA_DTO> would fail.
private List<ISyncInterface<Object>> _services2 = new List<ISyncInterface<Object>>();
void RegisterService<T, U>(T service)
where T : ISyncInterface<U>
{
_services.Add(service); // <- works e.g. for SyncServiceA
// _services2.Add(service); // <- FAILS for SyncServiceA - no conversion
// _services2.Add((ISyncInterface<Object>) service); // <- FAILS also - no explicit cast
}
}
// SETUP - The classes used above. Just to clarify.
class ServiceA_DTO { }
class ServiceB_DTO { }
class SyncServiceA : ISyncInterface<ServiceA_DTO>
{
public Task DoSync() {}
public IEnumerable<ServiceA_DTO> NewItems { get; }
}
class SyncServiceB : ISyncInterface<ServiceB_DTO>
{
public Task DoSync() {}
public IEnumerable<ServiceB_DTO> NewItems { get; }
}
这有可能吗?任何建议都非常感谢!
更新:新的,更详细的代码,以澄清问题。
下面有一个建议将通用接口建立在非通用接口上。但结果是,通用接口的所有实现类都必须实现非泛型方法,属性等 - 或者是否有办法绕过它?
感谢您的输入!
是否可以声明一个泛型集合只保存实现用任何
T
实例化的泛型接口的对象?
简答:不。
更长的回答:不,因为那没用。
让我们考虑一个简单的通用接口:
interface I<T> { T Get(); }
还有一堆实现它的对象:
class Lion : I<Lion>
{
public Lion Get() => this;
}
class TaxPolicyFactory : I<TaxPolicy>
{
public TaxPolicy Get() => new TaxPolicy();
}
class Door: I<Doorknob>
{
public Doorknob Get() => this.doorknob;
...
}
好的,现在假设你有一个像你想要的List<I<ANYTHING>>
:
var list = new List<I<???>> { new TaxPolicyFactory(), new Lion(), new Door() };
你有一张税收政策工厂,一只狮子和一扇门的清单。这些类型彼此没有任何共同之处;您无法对每个对象执行任何操作。即使你可以在每个上面打电话给Get
,那么你就会有一个税收政策,狮子和门把手的序列,你打算用它做什么?
没什么,那是什么。约束“为任何I<T>
实现接口T
”在C#中根本不是一个有用的约束,所以没有办法表达它。
听起来你有一个“XY”问题。这是一个问题,你有一个糟糕的解决方案,现在你问的是你的坏解决方案的问题。向我们提出一个关于你所遇到的真正问题的问题,而不是你为解决方案所做的坏主意。什么是真正的问题?
更新:随着问题中的新信息,现在更加明确。您想要的功能称为通用接口协方差,这是我最喜欢的C#4功能。
如果您将接口定义更新为
interface ISyncInterface<out T> { ... }
那么你可以在预期有ISyncInterface<String>
的环境中使用ISyncInterface<Object>
。例如,你可以将ISyncInterface<Giraffe>
放入List<ISyncInterface<Animal>>
或其他任何东西。
但是,您需要确保您的接口定义仅在共同有效的位置使用T
。您的界面如上所述是有效的,但是,例如,如果您想要将void M(T t);
方法添加到您的界面,它将不再具有协同有效性。 “out”是一个助记符,告诉你T
只能用作方法的输出。由于IEnumerable<T>
也有协同有效,所以很好;在T
没有IEnumerable<T>
的输入。
此外,方差仅适用于通用接口和委托,而变化类型必须是引用类型。您不能将ISyncInterface<int>
放入List<ISyncInterface<Object>>
,因为int
不是参考类型。
有关协方差和逆变的SO上有很多帖子;您还应该阅读Microsoft文档。这可能是一个令人困惑的功能。如果您对我们如何设计和实现该功能的历史细节感兴趣,请参阅我的博客。
也许你可以尝试这样的事情:
public interface MyInterface
{//methods common to all types
void FirstMethod();
}
public interface MyInterface<T> : MyInterface
{//methods specific to a type
void FirstMethod(T parameter);
}
public class MyClassThatHandlesAllInterfaces
{
private List<MyInterface> _allInterfacesT; //first interface in the chain
public void AddInterface<T>(MyInterface<T> ifToAdd)
{
_allInterfacesT.Add(ifToAdd); // <- this is what I'd like to do
}
}
我经常使用这种模式。因为我不知道您的方案的所有细节,所以它可能不适合您。
但它可能有助于其他人搜索谷歌。