【问题标题】:C# cant implement interface method because of different signatures (using generics)由于签名不同(使用泛型),C#无法实现接口方法
【发布时间】:2018-01-28 16:31:16
【问题描述】:

我有一个基本类和两个嵌套类。其中一个嵌套类正在实现一个接口,其中我有一个带有嵌套对象返回类型的方法签名。

这是我得到的:

A 类

using System;

namespace Nested
{
    class A
    {
        public class Item
        {
            //Implementation 
        }

        class B : IInterface
        {
            //
            public Item Get()
            {
                throw new NotImplementedException();
            }
        }
    }
}

A 类接口

namespace Nested
{
    internal interface IInterface
    {
        A.Item Get();
    }
}

与泛型相同

B 类

using System;


namespace Nested
{
    class A<T>
    {
        public class Item<T>
        {
            //Implementation 
        }

        class B<T> : IInterface<T>
        {
            //
            public Item<T> Get()
            {
                throw new NotImplementedException();
            }
        }
    }
}

B 类接口

namespace Nested
{
    internal interface IInterface<T>
    {
        A<T>.Item<T> Get();
    }
}

第一个不使用泛型的代码运行良好。与此相比,带有泛型的示例给了我以下错误:

Class1.cs(13,22): error CS0738: 'A<T>.B<T>' does not implement interface member 'IInterface<T>.Get()'. 'A<T>.B<T>.Get()' cannot implement 'IInterface<T>.Get()' because it does not have the matching return type of 'A<T>.Item<T>

为什么说接口使用 A&lt;T&gt;.Item&lt;T&gt; Get(); 和类 public Item&lt;T&gt; Get() 时返回类型不同?有什么想法吗?

编辑:停止将错误代码格式化为块引用,因为部分内容丢失了。这不是我收到的正确信息。

【问题讨论】:

  • 因为A.ItemA.Item&lt;T&gt; 是不同的类型,而你的接口契约是从Get 方法返回Item 而不是Item&lt;T&gt;
  • 接口说,它必须返回 A.Item Get();
  • 您收到一条警告,说明问题所在。 在此处提问之前,请注意编译器警告并理解它们。

标签: c# generics inner-classes


【解决方案1】:

当你有

class A<T>
{
    class B<T> { }
}

您应该(取决于您的设置)获得compiler warning CS0693

类型参数“T”与外部类型“A”的类型参数同名

这是因为泛型类中的嵌套类会获取外部类的类型参数,例如

class A<T>
{
   class B
   {
       public T Value { get; set; }
   {
}

完全有效 - B 获得与其外部类 A 相同的类型参数,因此可以像定义为非嵌套类 B&lt;T&gt; 一样使用它。

你的代码相当于

class A<T>
{
    class B<U> { }
}

或者说AB中的类型参数不一样,你没希望满足接口。

如果您忽略该警告(不推荐),可能会做一些可怕的事情:

#pragma warning disable 0693

public class A<T> where T : struct
{
    public class B<T> where T : class
    {
    }
}

#pragma warning restore 0693

如果A&lt;T&gt;B&lt;T&gt; 中的T 是相同的类型参数(一个类型不能同时是structclass),它就没有希望编译,而是只是非常混乱。

如果在 Visual Studio 中查看,IntelliSense 将显示:

所以A&lt;T&gt; 范围内的T B&lt;T&gt; 范围内的T 相同 - 后者隐藏前者。

事实上,没有什么可以阻止你拥有

var ab = new A<double>.B<Object>();

即使A&lt;T&gt;B&lt;T&gt; 的类型参数的名称 都是T。因此编译器警告。


我想你想要的是这样的:

class A<T>
{
    public class Item
    {
        //Implementation 
    }

    class B : IInterface<T>
    {
        public Item Get()
        {
            throw new NotImplementedException();
        }
    }
}

internal interface IInterface<T>
{
    A<T>.Item Get();
}

https://dotnetfiddle.net/nBFVLw查看这个答案的小提琴。

如果您不熟悉嵌套泛型类型的使用,它们可能会违反直觉。

【讨论】:

  • 想象一下,我得到了以下违反编译器错误的代码:class A&lt;T&gt; { class B&lt;T&gt; : IInterface&lt;T&gt;{ } } 这意味着,A 类的 &lt;T&gt;class B&lt;T&gt; 覆盖,因此 IInterface&lt;T&gt; 得到 B 级而不是 A 级,对吗?只是为了了解违规背后的逻辑。
  • 正确。在B&lt;T&gt; 内部,T 是应用于B&lt;T&gt;T,它可以不同于A&lt;T&gt;。我已经编辑了我的答案以添加更多细节。
【解决方案2】:

因为A.ItemA.Item&lt;T&gt; 是不同的类型,而你的接口契约是从Get 方法返回Item 而不是Item&lt;T&gt;

如果你在定义泛型类时,你也需要泛型接口,非泛型接口方法契约不适用于方法返回泛型类型,所以可能你也需要为泛型类型:

public interface  IInterface<T>
{
   A<T>.Item<T> Get<T>();
}

更新:

你的接口合约指定Get返回A&lt;T&gt;.Item&lt;T&gt;

A<T>.Item<T> Get();

虽然您的实现类型 B&lt;T&gt; 仅指定返回类型为 Item&lt;T&gt;

public Item<T> Get()
{
    throw new NotImplementedException();
}

由于哪个编译器不允许这样做

由于接口指定返回类型为A&lt;T&gt;.Item&lt;T&gt;,所以它也应该是B&lt;T&gt;类中Get方法的返回类型,否则它也会报错,当然A&lt;T&gt;.Item&lt;T&gt;Item&lt;T&gt;是然后不同,因此更改 B&lt;T&gt; 如下所示修复错误:

    class B<T> : IInterface<T>
    {
        //
        public A<T>.Item<T> Get<T>()
        {
            throw new NotImplementedException();
        }
    }

你可以看到下面的demo fiddle:

https://dotnetfiddle.net/f9Djbz

【讨论】:

  • Get() 中缺少类型参数,应该是 Get&lt;T&gt;()
  • 不知何故,stackoverflow 转换了我的错误消息,所以重要的部分丢失了。我改了。
  • 您需要提供完全限定的返回类型:class B&lt;T&gt; : IInterface&lt;T&gt; { // public A&lt;T&gt;.Item&lt;T&gt; Get&lt;T&gt;() { throw new NotImplementedException(); } }
  • public A.Item Get() {...} 正在修复它,谢谢。但是为什么我必须给出完全限定的返回类型呢?在第一个例子中,在A类中说public Item Get()就足够了,即使接口方法说A.Item Get()?
  • 你违反了compiler warning CS0693 - 看我的你的小提琴截图here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-28
  • 1970-01-01
  • 2021-11-30
  • 1970-01-01
相关资源
最近更新 更多