简体   繁体   中英

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

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.

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.

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. 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; 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."

While an array or a List implements IEnumerable, it is not an IEnumerable object. 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; } will not work, either. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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