首页新闻找找看学习计划

Add方法自动被调用

1
悬赏园豆:100 [已解决问题] 解决于 2013-07-29 11:30
 public class Users : IEnumerable<Users>
    {
        //public ObjectId id;
        public string Name { get; set; }
        public string Sex { get; set; }
        public int Age { get; set; }

        public void test()
        {
            var user111 = new Users { { "Name", "123" } };
        }

        public void Add(string Name, string Value)
        {

        }

        public IEnumerator<Users> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }
    }


很好奇,我在执行 var user111 = new Users { { "Name", "123" } }; 得知Add方法被自动调用了,这是为什么呢。

Add
冲动的主页 冲动 | 菜鸟二级 | 园豆:394
提问于:2013-07-28 23:46
< >
分享
最佳答案
0

觉得你的实现不好 User 和 Users 应该分开

public class User
{
        //public ObjectId id;
        public string Name { get; set; }
        public string Sex { get; set; }
        public int Age { get; set; }
}

public class Users : IEnumerable<User>
{
       List<User> mylist = new List<User>();

       public void Add(string Name, string Sex, int Age)
       {
            mylist.Add(new User{Name = Name, Sex = Sex,Age = Age});
       }        

        public IEnumerator<User> GetEnumerator()
        {
            return this.mylist.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

}
        
收获园豆:100
gunsmoke | 老鸟四级 |园豆:3592 | 2013-07-29 10:24

嗯,你好,我主要是想知道,我在执行 var user111 = new Users { { "Name", "123" } }; 得知Add方法被自动调用了,这是为什么呢。

冲动 | 园豆:394 (菜鸟二级) | 2013-07-29 10:33
````` | 园豆:14268 (专家六级) | 2013-07-29 10:54

@冲动: 因为你在new Users() 时用了 collection initializer,  的确就是个语法糖,

实际上就是创建Users之后执行了 Add method,  在集合中加入了一个new user

注意 IEnumable 理论上应该是只读的 不应该可以加入元素的。 所以 编译器会先创建一个 users2,  在其中加入user, 然后把集合置回给 users.  也就是你反编译得到的最终代码

gunsmoke | 园豆:3592 (老鸟四级) | 2013-07-29 11:04
其他回答(2)
2

应该是继承的问题。

1、IEnumerable<T>实现了Add(string Name, string Value)

2、Users继承了Ienumerable<T>。然后声明了同样签名的Add方法,这会覆盖掉“父类”的Add方法(这边是接口,所以是实现接口方法),实际上在编译的时候应该会给你一个提示,提示Add方法需要使用new关键字标识。不过只是提示而已。。。比较规范的定义应该是

public new void Add(string Name, string Value)
        {

        }

3、当你new Users(){{"Name","123"}}的时候,会用到集合初始化器,此时Ienumerable<T>会调用Add方法,这样就调用到了新的Add方法

滴答的雨 | 园豆:3690 (老鸟四级) | 2013-07-29 00:16

Add并不是实现接口得来的。实现接口只有2个方法

        public IEnumerator<Users> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }
支持(0) 反对(0) 冲动 | 园豆:394 (菜鸟二级) | 2013-07-29 10:09

@冲动:上面回答的确实有点问题,我没认真看是实现接口,看是秒了下以为是继承类。不过这里运用到的特性还是集合初始化器

我搜索到一部分关于集合初始化器的描述

集合初始化器

与对象初始化语法类似的是集合初始化。这个语法使得我们可以用简单的数 组类型来初始化一个泛型容器(比如List)。可以应用集合初始化器 的对象的类型必须实现了System.Collections.Generic.ICollections 并指定了确定的T。此外,必须存在从每个元素初始化器的类型到T的隐式转换。 如果这些条件不能满足,就会产生一个编译期错误。集合初始化器将依次对每个 指定的元素调用ICollection.Add(T)。在这个约束之下, System.Collection命名空间下的容器(比如ArrayList)就不能使用这种新语法 ,因为它们并没有实现所需的接口。

一个集合初始化器由一系列的元素初始化器构成,包围在{和}记号之间,并 使用逗号进行分隔。每个元素初始化器指定一个元素,该元素将被添加到待初始 化的集合对象中。为了避免与成员初始化器混淆,元素初始化器不能是赋值表达 式。

http://www.shangxueba.com/jingyan/95309.html

那看来这个集合初始化器语法糖是搜索匹配参数的Add()方法而不是ICollection接口的Add()方法。

支持(0) 反对(0) 滴答的雨 | 园豆:3690 (老鸟四级) | 2013-07-29 11:11
1

直接反编译代码看下是怎么一回事

chenping2008 | 园豆:9836 (大侠五级) | 2013-07-29 10:03

用Refector反编译出来竟然是这个样子。。。我想知道,为什么我实现了这个接口,这样声明,会有这种效果。

支持(0) 反对(0) 冲动 | 园豆:394 (菜鸟二级) | 2013-07-29 10:16
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册