为什么喜欢构图而不是继承呢?每种方法都有哪些权衡取舍?什么时候应该选择继承而不是作文?
任何人都可以向我解释为什么我想在C#中使用IList而不是List?
相关问题:为什么暴露它被认为是不好的List<T>
好吧,这真的很难承认,但我现在确实有很强的诱惑力来继承std::vector.
我需要大约10个定制的矢量算法,我希望它们直接成为矢量的成员.但我自然也希望拥有剩下std::vector的界面.好吧,作为一个守法的公民,我的第一个想法是std::vector在MyVector课堂上有一个成员.但是我必须手动重新编写所有std :: vector的接口.打字太多了.接下来,我考虑了私有继承,所以我不会using std::vector::member在公共部分写一些方法而不是重新提取方法.实际上这也很乏味.
在这里,我确实认为我可以简单地从公开继承std::vector,但在文档中提供警告,不应该多态地使用此类.我认为大多数开发人员都有足够的能力去理解这不应该以多态方式使用.
我的决定绝对没有道理吗?如果是这样,为什么?你能提供一个替代方案,其他成员实际上是成员,但不会涉及重新输入所有vector的界面吗?我对此表示怀疑,但如果可以,我会很高兴.
此外,除了一些白痴可以写类似的事实
std::vector<int>* p = new MyVector
Run Code Online (Sandbox Code Playgroud)
使用MyVector 有任何其他现实危险吗?通过说现实,我放弃像想象一个带有指向矢量的指针的函数...
好吧,我已经陈述了我的情况.我犯罪了.现在由你来原谅我了不起:)
一位同事今天问我如何为一个系列添加一个范围.他有一个继承自的课程Collection<T>.这种类型的get-only属性已包含一些项目.他想将另一个集合中的项目添加到属性集合中.他怎么能以C#3友好的方式这样做呢?(注意关于get-only属性的约束,这会阻止像执行Union和重新分配这样的解决方案.)
当然,与物业的foreach.添加将工作.但是A List<T>风格的AddRange会更加优雅.
编写扩展方法很容易:
public static class CollectionHelpers
{
public static void AddRange<T>(this ICollection<T> destination,
IEnumerable<T> source)
{
foreach (T item in source)
{
destination.Add(item);
}
}
}
Run Code Online (Sandbox Code Playgroud)
但我感觉我正在重新发明轮子.我没有发现任何类似System.Linq或morelinq.
糟糕的设计?只需致电添加?缺少明显的?
LINQ Count()方法是否比List<>.Count或更快或更慢Array.Length?
我似乎在围绕C#中的通用列表通用列表的想法时遇到了一些麻烦.我认为问题源于<T>参数的使用,我之前没有经验.有人可以提供一个简短的例子,声明一个List是一个List,其中包含另一个List,但其中包含的对象的类型不是立即知道的?
我一直在阅读有关泛型的MS文档,我不能立即确定是否可以声明一个List<List<T>>,也不确定如何将<T>参数传递给内部列表.
编辑:添加信息
会宣布List<List<T>>在这里被视为合法吗?如果您想知道,我正在构建一个类,允许我使用ulong作为索引器,并且(希望)通过维护列表列表来绕过令人讨厌的2GB限制.Net.
public class DynamicList64<T>
{
private List<List<T>> data = new List<List<T>>();
private ulong capacity = 0;
private const int maxnumberOfItemsPerList = Int32.MaxValue;
public DynamicList64()
{
data = new List<List<T>>();
}
Run Code Online (Sandbox Code Playgroud) 实现继承自的新类的最快方法是什么List<T>?
class Animal {}
class Animals : List<Animal> {} // (1)
Run Code Online (Sandbox Code Playgroud)
我遇到的一个问题:通过简单地做(1),我发现我没有从继承任何构造函数中获益List<T>.
最后,我想Animals表现得很像List<T>(例如,可以构建,与Linq的兼容性).但另外,我还希望能够添加自己的自定义方法.
考虑下面doSomething(List<Object>)接受List<Object>作为参数的方法.
private void doSomething(List<Object> list) {
// do something
}
Run Code Online (Sandbox Code Playgroud)
现在考虑下面的代码片段,它试图调用doSomething()我尝试传递List<String>给的地方doSomething()
List<Object> objectList;
List<String> stringList;
doSomething(stringList); // compilation error incompatible types
doSomething(objectList); // works fine
Run Code Online (Sandbox Code Playgroud)
即使在代码下面也会引发编译错误
objectList = stringList; // compilation error incompatible types
Run Code Online (Sandbox Code Playgroud)
我的问题是为什么List<String>不能传递给接受的方法List<Object>?
考虑以下课程:
public class Cars extends Observable{
private ArrayList<String> carList = new ArrayList<String>();
public void addToCarList(String car){
// ...
hasChanged();
notifyObservers();
}
public void removeFromCarList(String car){
// ...
hasChanged();
notifyObservers();
}
public ArrayList<String> getCarList() {
return carList;
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,每次更改carList时,我都要通知Observers.如果有人这样做getCarList().add(...);,这就被规避了.
我如何提供carList对它的读访问权(用于迭代它等),但是除了特殊方法addToCarList和removeFromCarList?之外,它阻止对它的写访问 ?
我想到了这个:
public ArrayList<String> getCarList() {
return (ArrayList<String>)carList.clone();
}
Run Code Online (Sandbox Code Playgroud)
但是有人使用我的课程,在向克隆添加一些内容时carList,不会被告知这不是它的意图.
static void Main(string[] args)
{
List<int> listArray = new List<int>();
listArray.Add(100);
foreach (int item in listArray)
Console.WriteLine(item);
}
Run Code Online (Sandbox Code Playgroud)
a)在foreach声明中呼吁listArray's IEnumerable<int>.GetEnumerator()实现,它通过调用它listArray.GetEnumerator()或IEnumerable<int>.GetEnumerator()或 IEnumerable.GetEnumerator()?
b)同样,当foreach引用对象返回时listArray's IEnumerable<int>.GetEnumerator(),它是通过引用IEnumerator还是IEnumerator<int>引用类型引用该对象?
谢谢
编辑:
我的一些问题将引用此文:
o使用标识符GetEnumerator对类型X执行成员查找,而不使用类型参数.如果成员查找不产生匹配,或者产生歧义,或产生不是方法组的匹配,请检查可枚举接口,如下所述.如果成员查找产生除方法组或不匹配之外的任何内容,建议发出警告.
o使用生成的方法组和空参数列表执行重载解析.如果重载决策导致没有适用的方法,导致歧义,或导致单个最佳方法但该方法是静态的或不公开的,请检查可枚举的接口,如下所述.如果重载决策产生除明确的公共实例方法或没有适用的方法之外的任何内容,建议发出警告.
o如果GetEnumerator方法的返回类型E不是类,结构或接口类型,则会产生错误,并且不会采取进一步的步骤.
o在E上执行成员查找,标识符为Current,没有类型参数.如果成员查找不产生匹配,则结果是错误,或者结果是除允许读取的公共实例属性之外的任何内容,产生错误并且不执行进一步的步骤.
o成员查找在E上执行,标识符为MoveNext,没有类型参数.如果成员查找不产生匹配,则结果是错误,或者结果是除方法组之外的任何内容,产生错误并且不执行进一步的步骤.
o使用空参数列表对方法组执行重载分辨率.如果重载决策导致没有适用的方法,导致歧义,或导致单个最佳方法但该方法是静态的或非公共的,或者其返回类型不是bool,则产生错误并且不采取进一步的步骤.
o集合类型为X,枚举器类型为E,元素类型为Current属性的类型.
否则,检查一个可枚举的接口:o如果只有一个类型T,从而存在从X到接口System.Collections.Generic.IEnumerable的隐式转换,那么集合类型就是这个接口,枚举器类型就是接口System.Collections.Generic.IEnumerator,元素类型为T.
否则,如果存在多个这样的类型T,则产生错误并且不采取进一步的步骤.
否则,如果存在从X到System.Collections.IEnumerable接口的隐式转换,则集合类型为此接口,枚举器类型为接口System.Collections.IEnumerator,元素类型为object.
否则,将产生错误,并且不会采取进一步的步骤.
1)
引自Eric Lippert:
选项(1)是正确的.请注意,这意味着返回的枚举器是一个未装箱的可变结构.
事实上,这是一个可变的结构,如果你做一些愚蠢的事情,比如传递结构,就像它是一个引用类型一样,它具有非常实际的效果; 它将按值复制,而不是通过引用复制.
来自http://en.csharp-online.net/ECMA-334:_15.8.4_The_foreach_statement:
foreach(V v in x)嵌入式语句
然后扩展到:
Run Code Online (Sandbox Code Playgroud){ E e = ((C)(x)).GetEnumerator(); try { V v; while (e.MoveNext()) { …
c# ×6
inheritance ×3
.net ×2
collections ×2
generics ×2
java ×2
list ×2
oop ×2
aggregation ×1
c#-3.0 ×1
c++ ×1
casting ×1
composition ×1
linq ×1
stl ×1
vector ×1