【问题标题】:Problem implementing a generic method in a generic type which inherits from a non-generic interface在从非泛型接口继承的泛型类型中实现泛型方法的问题
【发布时间】:2025-11-29 13:40:01
【问题描述】:

我有一个带有两个通用方法签名的非通用接口。

interface IDataContainer
{
    T GetValue<T>();
    void SetValue<T>(T value);
}

然后我有一个实现 IDataContainer 的泛型类

public class DataContainer<T>: IDataContainer
{
    private T _value;

    #region IDataContainer Members

    public T GetValue<T>()
    {
        return _value;
    }

    public void SetValue<T>(T value)
    {
        _value = value;
    }

    #endregion
}

我收到一个错误,提示无法在已实现的 GetValue 和 SetValue 方法上将类型 T 隐式转换为 T。

有没有办法解决这个问题?某种类型的平等约束?有没有更好的办法?

我知道我可以通过将 IDataContainer 设为 IDataContainer&lt;T&gt; 来使其成为泛型,但是当 T 并不总是相同类型时,我无法拥有 IDataContainers 列表。

【问题讨论】:

    标签: c# .net generics


    【解决方案1】:

    您的问题是编译器看到两种不同的类型。 IDataContainer 范围内的 T 与泛型方法范围内的 T 不同,因此编译器会抱怨。

    因为你的容器包含一个 T 的实例,我认为你的接口也应该有类型参数 T(不仅仅是一个方法范围的泛型参数)。

    您当前的接口实际上承诺(请记住,接口是合同),能够为任何 T 提供 T 值 - 这肯定不是您想要的吗?

    【讨论】:

      【解决方案2】:

      您的代码的意图将在通用接口中很好地捕捉到:

      interface IDataContainer<T> {
        T GetValue();
        void SetValue(T value);
      }
      

      那么为什么你有一个带有泛型方法的非泛型接口呢?

      泛型方法的问题是类型参数不一样,虽然它们有相同的名字。

      要在 T 不相同时获得数据容器列表,只需为您的通用接口提供一个非通用基础接口:

      interface IDataContainer { }
      
      interface IDataContainer<T> : IDataContainer { 
        ...
      }
      

      那么你就可以有一个非泛型数据容器的列表了。

      【讨论】:

      • 但是当 T 并不总是相同类型时,我无法获得 IDataContainers 列表。
      【解决方案3】:

      这两种方法意味着两种不同的东西。在 IDataContainer 中,您指定一个泛型方法。这可以用任何类型调用。在DataContainer 中,您指定采用类中指定的特定类型参数的方法。 IDataContainer 的合同不满足 DataContainer。您应该更改 IDataContainer 使其具有通用性。

      为了更清楚,请单独考虑IDataContainer。无论getContainer()返回的具体容器如何,以下代码都应该是合法的

      IDataContainer ctr = getContainer();
      String x = ctr.getValue<String>();
      

      但是,如果 getContainer 如下所示,那么如果您的代码是合法的,那么该代码显然会中断:

      public IDataContainer getContainer() {
          return new DataContainer<Foo>();
      }
      

      您遇到的根本问题是,如果您有不同类型的 DataContainers,那么这些 DataContainers 的合同就根本不同。 DataContainer&lt;Foo&gt; 有一个GetValue 给你一个Foo,而DataContainer&lt;Bar&gt; 有一个GetValue 给你一个Bar。如果 Foo 和 Bar 都有一个超类,那么您可以使用它,否则,您将进行强制转换,因为如果将它们一起放入一个列表中,您根本无法保证类型安全。

      【讨论】:

        最近更新 更多