简体   繁体   English

c#接口实现 - 为什么这不构建?

[英]c# interface implemention - why does this not build?

Sorry if this has been asked before but it's virtually impossible to google. 很抱歉,如果之前已经询问过,但谷歌几乎不可能。 I think that an int array implements IEnumerable and therefore Thing should be able to implement IThing. 我认为int数组实现IEnumerable,因此Thing应该能够实现IThing。 How come it doesn't? 怎么没有?

public interface IThing
{
    IEnumerable<int> Collection { get; }
}

public class Thing : IThing
{
    public int[] Collection { get; set; }
}

note that 注意

public class Thing : IThing
{
    public int[] Array { get; set; }
    public IEnumerable<int> Collection
    {
         get
         {
              return this.Array;
         }
    }
}

is fine. 很好。

对于要实现的接口,方法签名和返回类型必须相同,因此int []可转换为IEnumerable这一事实对我来说没什么区别。

The return type of the properties in the different implementations is different - returning a int[] is not the same as returning a IEnumerable<int> . 不同实现中属性的返回类型是不同的 - 返回int[]与返回IEnumerable<int>

As far as implementing the interface - the types must match exactly . 就实现接口而言 - 类型必须完全匹配。

This should work just fine: 这应该工作得很好:

public class Thing : IThing
{
    public IEnumerable<int> Collection { get; set; }
}

The interface implementation must implement the interface exactly. 接口实现必须完全实现接口。 This prevents you from returning a type that implements that interface as the member. 这可以防止您返回实现该接口的类型作为成员。

If you wish to do this, one option is to implement the interface explicitly : 如果您希望这样做,一个选项是明确实现接口:

public interface IThing
{
    IEnumerable<int> Collection { get; }
}

public class Thing : IThing
{
    public int[] Collection { get; set; }
    IEnumerable<int> IThing.Collection { get { return this.Collection; } }
}

This allows your public API for the class to use the concrete type, but the interface implementation to be fulfilled correctly. 这允许类的公共API使用具体类型,但接口实现要正确实现。

For example, with the above, you can write: 例如,有了上述内容,您可以编写:

internal class Test
{
    private static void Main(string[] args)
    {
        IThing thing = new Thing { Collection = new[] { 3, 4, 5 } };

        foreach (var i in thing.Collection)
        {
            Console.WriteLine(i);
        }
        Console.ReadKey();
    }
}

您的实现应该完全按照原样实现接口。

Because the signature of 因为签名了

IEnumerable<int> Collection { get; }

Is not the same than the signature of 与签名不一样

int[] Collection { get; set; }

And when you implement an interface, the signatures should be exactly the same. 当您实现接口时,签名应该完全相同。

This is where covariance / contravariance can come in handy. 这就是协方差/逆变可以派上用场的地方。 This feature lets you define in/out tags on your generics and lets you do the following: 此功能允许您在泛型上定义输入/输出标记,并允许您执行以下操作:

public interface IThing<out T> where T : IEnumerable<int> {
    T Collection { get; }
}

public class Thing : IThing<int[]> {
    public int[] Collection { get; set; }
}

Then that will allow you to define other implementations, and then still use them together as IThing<IEnumerable<int>> s. 然后,这将允许您定义其他实现,然后仍然将它们一起用作IThing<IEnumerable<int>> s。

public class Thing2 : IThing<List<int>> {
    public List<int> Collection { get; set; }
}

class Program {
    static void Main() {
        var x = new Thing();
        var y = new Thing2();
        new List<IThing<IEnumerable<int>>> { x, y };
    }
}

The advantage of this approach over the explicit interface implementation is that you guarantee that IThing.Collection is the exact same method as Thing.Collection, whereas with explicit implementation, they're actually different methods so there's no such guarantee. 这种方法优于显式接口实现的优点是,您可以保证 IThing.Collection与Thing.Collection完全相同,而在显式实现时,它们实际上是不同的方法,因此没有这样的保证。 The disadvantage of course being that you have to be a little more explicit and so it makes the code a bit "noisier" to look at. 缺点当然是你必须更加明确,因此它使代码看起来有点“吵闹”。

Not sure why the C# compiler couldn't figure this out implicitly; 不确定为什么C#编译器无法隐含地解决这个问题; my guess being that it'd just take too long to compile with that extra check. 我的猜测是,用额外的检查编译只需要太长时间。

If you read the definition of Interfaces you'll notice that it says "...the corresponding member of the class must be public, non-static, and have the same name and signature as the interface member." 如果您阅读了Interfaces的定义,您会注意到它表示“......该类的相应成员必须是公共的,非静态的,并且与接口成员具有相同的名称和签名。”

While an array or a List implements IEnumerable, it is not an IEnumerable object. 虽然数组或List实现IEnumerable,但它不是 IEnumerable对象。 That's your problem. 那是你的问题。

Your signature must match for it to work. 您的签名必须匹配才能生效。 You'll notice that public List<int> Collection { get; set; } 您会注意到public List<int> Collection { get; set; } public List<int> Collection { get; set; } public List<int> Collection { get; set; } will not work, either. public List<int> Collection { get; set; }也行不通。 You will either need to change your Interface's property definition, or have your implementation return an IEnumerable <int> as you have with your second working example. 您将需要更改Interface的属性定义,或者让您的实现返回IEnumerable <int>就像您的第二个工作示例一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM