持有任何的“强类型”通用集合 给定接口/类的

问题描述 投票:0回答:2

是否可以声明一个泛型集合只保存实现任何<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; } 
}

这有可能吗?任何建议都非常感谢!

更新:新的,更详细的代码,以澄清问题。

下面有一个建议将通用接口建立在非通用接口上。但结果是,通用接口的所有实现类都必须实现非泛型方法,属性等 - 或者是否有办法绕过它?

感谢您的输入!

c# generic-collections
2个回答
3
投票

是否可以声明一个泛型集合只保存实现用任何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文档。这可能是一个令人困惑的功能。如果您对我们如何设计和实现该功能的历史细节感兴趣,请参阅我的博客。


0
投票

也许你可以尝试这样的事情:

  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
    }
  }

我经常使用这种模式。因为我不知道您的方案的所有细节,所以它可能不适合您。

但它可能有助于其他人搜索谷歌。

© www.soinside.com 2019 - 2024. All rights reserved.