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方法被自动调用了,这是为什么呢。
觉得你的实现不好 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(); } }
嗯,你好,我主要是想知道,我在执行 var user111 = new Users { { "Name", "123" } }; 得知Add方法被自动调用了,这是为什么呢。
@冲动: 因为你在new Users() 时用了 collection initializer, 的确就是个语法糖,
实际上就是创建Users之后执行了 Add method, 在集合中加入了一个new user
注意 IEnumable 理论上应该是只读的 不应该可以加入元素的。 所以 编译器会先创建一个 users2, 在其中加入user, 然后把集合置回给 users. 也就是你反编译得到的最终代码
应该是继承的问题。
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方法
Add并不是实现接口得来的。实现接口只有2个方法
public IEnumerator<Users> GetEnumerator() { throw new NotImplementedException(); } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
@冲动:上面回答的确实有点问题,我没认真看是实现接口,看是秒了下以为是继承类。不过这里运用到的特性还是集合初始化器
我搜索到一部分关于集合初始化器的描述
集合初始化器
与对象初始化语法类似的是集合初始化。这个语法使得我们可以用简单的数 组类型来初始化一个泛型容器(比如List)。可以应用集合初始化器 的对象的类型必须实现了System.Collections.Generic.ICollections 并指定了确定的T。此外,必须存在从每个元素初始化器的类型到T的隐式转换。 如果这些条件不能满足,就会产生一个编译期错误。集合初始化器将依次对每个 指定的元素调用ICollection.Add(T)。在这个约束之下, System.Collection命名空间下的容器(比如ArrayList)就不能使用这种新语法 ,因为它们并没有实现所需的接口。
一个集合初始化器由一系列的元素初始化器构成,包围在{和}记号之间,并 使用逗号进行分隔。每个元素初始化器指定一个元素,该元素将被添加到待初始 化的集合对象中。为了避免与成员初始化器混淆,元素初始化器不能是赋值表达 式。
http://www.shangxueba.com/jingyan/95309.html
那看来这个集合初始化器语法糖是搜索匹配参数的Add()方法而不是ICollection接口的Add()方法。
直接反编译代码看下是怎么一回事
用Refector反编译出来竟然是这个样子。。。我想知道,为什么我实现了这个接口,这样声明,会有这种效果。