【问题标题】:How to delegate interface implementation to other class in C#如何将接口实现委托给C#中的其他类
【发布时间】:2008-09-24 09:14:16
【问题描述】:

假设以下类:

public class MyEnum: IEnumerator
{
    private List<SomeObject> _myList = new List<SomeObject>();
...
}

必须在 MyEnum 中实现 IEnumerator 方法。 但是是否可以直接将 IEnumerator 的实现“委托”或重定向到 _myList 而无需实现 IEnumerator 方法?

【问题讨论】:

    标签: c# interface


    【解决方案1】:

    方法一: 继续使用封装并将调用转发到 List 实现。

    class SomeObject
    {
    }
    
    class MyEnum : IEnumerable<SomeObject>
    {
        private List<SomeObject> _myList = new List<SomeObject>();
    
        public void Add(SomeObject o)
        {
            _myList.Add(o);
        }
    
        public IEnumerator<SomeObject> GetEnumerator()
        {
            return _myList.GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            MyEnum a = new MyEnum();
            a.Add(new SomeObject());
    
            foreach (SomeObject o in a)
            {
                Console.WriteLine(o.GetType().ToString());
            }
    
            Console.ReadLine();
        }
    }
    

    方法二: 从 List 实现继承,您可以免费获得该行为。

    class SomeObject
    {
    }
    
    class MyEnum : List<SomeObject>
    {
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            MyEnum a = new MyEnum();
            a.Add(new SomeObject());
    
            foreach (SomeObject o in a)
            {
                Console.WriteLine(o.GetType().ToString());
            }
    
            Console.ReadLine();
        }
    }
    

    方法 1 允许更好的沙盒,因为没有 MyEnum 知识就不会在 List 中调用任何方法。为了最少的努力,方法 2 是首选。

    【讨论】:

    • 为方法 1 提供一些语法糖速记符号肯定会很好,例如private readonly IEnumerable&lt;SomeObject&gt; _myList implements IEnumerable&lt;SomeObject&gt;; 之类的东西(借用了 Delphi 的语法)。有谁知道是否曾经考虑过这样的事情,如果有,为什么它还没有被添加到 C# 中?
    【解决方案2】:

    你可以这样做:

    public class MyEnum : IEnumerator {
        private List<SomeObject> _myList = new List<SomeObject>();
        public IEnumerator GetEnumerator() { return this._myList.GetEnumerator(); }
    }
    

    原因很简单。您的类可以包含多个作为集合的字段,因此编译器/环境无法知道应该使用哪个字段来实现“IEnumerator”。

    EIDT:我同意@pb - 你应该实现 IEnumerator 接口。

    【讨论】:

    • 要实现的接口是IEnumerable而不是IEnumerator。
    【解决方案3】:

    除了使用 pb 的方法之外,这是不可能的,原因很“简单”:接口方法需要传递一个this 指针作为第一个参数。当您在对象上调用 GetEnumerator 时,此指针将成为您的对象。但是,为了使调用在嵌套列表上起作用,指针必须是对该列表的引用,而不是您的类。

    因此,您必须明确地将方法委托给另一个对象。

    (顺便说一句,另一个回复中的建议是正确的:使用IEnumerator&lt;T&gt;不是 IEnumerable!)

    【讨论】:

      【解决方案4】:

      如果您想以调用者无法修改集合的方式返回集合,您可能希望将 List 包装到 ReadOnlyCollection 并返回 ReadOnlyCollection 的 IEnumerable。

      这样您就可以确保您的收藏不会被更改。

      【讨论】:

        【解决方案5】:

        除非您从 List 派生,否则不会。

        public class MyEnum : List<SomeObject>, IEnumerable<SomeObject>{}
        

        【讨论】:

        • 好的,这会起作用,但我想确保调用代码无法再次将枚举数类型转换为 List 并从中添加或删除对象。
        【解决方案6】:

        感谢大家的意见和解释。 最终,我将您对以下问题的一些答案结合起来:

            class MyEnum : IEnumerable<SomeObject>
        {
            private List<SomeObject> _myList = new List<SomeObject>();
            public IEnumerator<SomeObject> GetEnumerator()
            {
                // Create a read-only copy of the list.
                ReadOnlyCollection<CustomDevice> items = new ReadOnlyCollection<CustomDevice>(_myList);
                return items.GetEnumerator();
            }
        }
        

        此解决方案是确保调用代码无法修改列表,并且每个枚举数在各个方面都独立于其他枚举数(例如,使用排序)。 再次感谢。

        【讨论】:

        • 你可以绕过ReadOnlyCollection,因为IEnumerables 无论如何都是不可变的!用户必须向上转换并猜测列表的原始类型才能修改它。恕我直言,复制列表不是一个好主意。
        【解决方案7】:

        请注意,感谢duck-typing,您可以在任何具有GetEnumerator 方法的对象上使用foreach - 对象类型不需要实际实现IEnumerable

        如果你这样做:

        class SomeObject
        {
        }
        
         class MyEnum
         {
            private List<SomeObject> _myList = new List<SomeObject>();
        
            public IEnumerator<SomeObject> GetEnumerator()
            {
                return _myList.GetEnumerator();
            }
         }
        

        这样就可以了:

        MyEnum objects = new MyEnum();
        // ... add some objects
        foreach (SomeObject obj in objects)
        {
            Console.WriteLine(obj.ToString());
        }
        

        【讨论】:

        • 我意识到这不是对原始问题的一般答案,但它与问题中提供的特定用例有关。
        • 如果您意识到自己没有回答问题,那么不要发布问题的答案。答案是为了回答问题,而不是为了发布您觉得有趣的随机琐碎事实。在这种情况下,这实际上并不能帮助您;在这种情况下,您没有理由不实际实现该接口。
        • 问题是如何委托接口的实现以避免编写样板代码。我的回答是对委托实施 IEnumerable 的常见情况的潜在答案,这也恰好是 OP 使用的示例。我争论是否将其作为评论或答案,并决定将其作为答案。它对特定形式的问题的回答。
        • 然而,您在整个答案中都在谈论如何不需要实际实现接口,在这种情况下这不是必要的,甚至是没有帮助或可取的。您只是在解释一个离题,没有帮助,切题,而不是实际回答问题。这使得它不是一个答案(甚至不是一个有用的评论)。
        • 请重新阅读原始问题的正文:“是否可以直接将 IEnumerator 的实现“委托”或重定向到 _myList 而无需实现 IEnumerator 方法?” i> - 我的回答非常直接地解决了这个问题。
        猜你喜欢
        • 1970-01-01
        • 2011-03-29
        • 1970-01-01
        • 2018-03-12
        • 2018-05-07
        • 1970-01-01
        • 2010-12-19
        • 1970-01-01
        • 2012-07-05
        相关资源
        最近更新 更多