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

发布于 2024-12-17 11:13:36 字数 513 浏览 2 评论 0 原文

抱歉,如果之前有人问过这个问题,但实际上不可能用谷歌搜索。我认为 int 数组实现了 IEnumerable,因此 Thing 应该能够实现 IThing。怎么没有呢?

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

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

请注意,这

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

很好。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

俯瞰星空 2024-12-24 11:13:36

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

For an interface to be implemented the method signature and return type must be identical, so the fact that an int[] is convertible to an IEnumerable makes no difference I'm afraid.

情绪少女 2024-12-24 11:13:36

接口实现必须准确实现接口。这会阻止您返回实现该接口作为成员的类型。

如果您希望这样做,一种选择是显式实现接口:

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

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

这允许类的公共 API 使用具体类型,但可以正确实现接口实现。

例如,通过上面的内容,您可以编写:

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();
    }
}

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();
    }
}
谢绝鈎搭 2024-12-24 11:13:36

不同实现中属性的返回类型不同 - 返回 int[] 与返回 IEnumerable 不同。

就实现接口而言 - 类型必须完全匹配

这应该可以正常工作:

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

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; }
}
只为一人 2024-12-24 11:13:36

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

Your implementations should implement interface exactly as it is.

ㄟ。诗瑗 2024-12-24 11:13:36

因为 的签名

IEnumerable<int> Collection { get; }

与 的签名不一样

int[] Collection { get; set; }

并且当您实现接口时,签名应该完全相同。

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.

滿滿的愛 2024-12-24 11:13:36

这就是协变/逆变可以派上用场的地方。此功能允许您在泛型上定义输入/输出标记,并允许您执行以下操作:

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

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

然后,您可以定义其他实现,然后仍然将它们一起用作 IThing>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 };
    }
}

与显式接口实现相比,这种方法的优点是您保证 IThing.Collection 与 Thing.Collection 完全相同,而使用显式实现时,它们实际上是不同的方法,因此不存在这样的方法保证。当然,缺点是您必须更明确一点,因此它使代码看起来有点“嘈杂”。

不知道为什么 C# 编译器无法隐式地解决这个问题;我的猜测是,使用额外的检查进行编译会花费太长时间。

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.

绝情姑娘 2024-12-24 11:13:36

如果您阅读接口的定义,您会注意到它说“ ...类的相应成员必须是公共的、非静态的,并且与接口成员具有相同的名称和签名。”

虽然数组或列表实现了 IEnumerable,但它不是 IEnumerable 对象。那是你的问题。

您的签名必须匹配才能正常工作。您会注意到 public List;集合{获取;放; } 也不起作用。您需要更改接口的属性定义,或者让您的实现返回 IEnumerable ,就像第二个工作示例一样。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文