提问人:sbi 提问时间:10/29/2009 更新时间:10/30/2009 访问量:2611
C# 中的泛型类型:将类型参数限制为集合
Generic type in C#: restricting the type parameter to be a collection
问:
我需要编写一个泛型类,其中类型参数必须是实现的东西。在里面,我需要集合的项目类型(在标记为 的代码片段中)。ICollection<T>
MyClass
???
class MyClass<TCollection> where TCollection : ICollection<???>
{
// ...
public void store(??? obj) { /* put obj into collection */ }
// ...
}
通常,集合实际上是一本字典。有时,它会是一个简单的列表。
我确切地知道如何在 C++ 中做到这一点。我该怎么做是 C#?
答:
好吧,你通常会使用另一个类型参数来做到这一点:
class MyClass<TCollection, TElement> where TCollection : ICollection<TElement>
{
// ...
public void store(TElement obj) { }
// ...
}
在这种情况下,您真的需要吗?你能凑合着过吗?TCollection
TElement
评论
MyClass
TCollection
TElement
TElement
MyClass
:(
你就不能这样做吗?
class MyClass<T, TCollection> where T: YourTypeOrInterface
where TCollection : ICollection<T>
{
public void store(T obj) { }
}
而且,没有经过测试,但我能想到的唯一其他方法是在存储项目时指定类型:
class MyClass<TCollection> where TCollection : System.Collections.ICollection
{
TCollection Collection;
public void Store<T>(T obj)
{
((ICollection<T>)this.Collection).Add(obj);
}
}
最简单的做法是只指定元素类型,并在需要的地方进行硬编码,例如ICollection<T>
class MyClass<T> {
private ICollection<T> _items;
public MyClass(ICollection<T> items) {
_items = items;
}
public void Store(T obj) {
_items.Add(obj);
}
public ICollection<T> Items {
get {
return _items;
}
}
}
我建议您将集合实例传递给构造函数,而不是在内部创建一个。它使类更简单、更“通用”(请原谅双关语),并允许您使用非默认构造函数构造集合实例,例如,使用非默认比较器的字典。
重新编辑(第 3 次尝试):使用类继承和命名空间别名进行模拟在某种程度上都是可以的,但在某些情况下,这两种抽象都会崩溃。这段代码是我发现的最简单的实际编译代码。typedef
步骤 1 - 定义这些类:
// This KeyValuePair was being used to simulate a tuple. We don't need to simulate a tuple when we have a concrete class.
class BazAndListOfWrgl {
Baz Baz { get; set; }
List<Wrgl> Wrgls { get; set; }
}
// Simple typedef.
class BazAndListOfWrglDictionary : Dictionary<Bar, BazAndListOfWrgl> { }
步骤 2 - 定义这些命名空间别名。所有标识符都必须是完全限定的。引用的所有类型都必须已在不同的物理文件中定义(因为命名空间别名必须位于文件中的所有代码之前)。
using OuterDictionary = System.Collections.Generic.Dictionary<MyNamespace.Foo, MyNamespace.BazAndListOfWrglDictionary>;
using OuterDictionaryItem = System.Collections.Generic.KeyValuePair<MyNamespace.Foo, MyNamespace.BazAndListOfWrglDictionary>;
第 3 步 - 像这样使用它们:
class Program {
static void Main() {
// List-based example.
var listWrapper = new MyClass<BazAndListOfWrgl>(new List<BazAndListOfWrgl>());
listWrapper.Store(new BazAndListOfWrgl());
Console.WriteLine(listWrapper.Items.Count);
// Dictionary-based example.
var dictionaryWrapper = new MyClass<OuterDictionaryItem>(new OuterDictionary());
dictionaryWrapper.Store(new OuterDictionaryItem(new Foo(), new BazAndListOfWrglDictionary()));
Console.WriteLine(dictionaryWrapper.Items.Count);
}
}
理由是:不能是命名空间别名,因为命名空间别名不能相互依赖。 并且不能是派生类,否则编译器不会将一个类识别为另一个类的元素。BazAndListOfWrglDictionary
OuterDictionary
OuterDictionaryItem
评论
:-x
ICollection<T> _items
T
ICollection<T>
ICollection<T>
KeyValuePair
这对我有用:
class MyClass<TCollection,T> where TCollection : ICollection<T> , new()
{
private TCollection collection;
public MyClass()
{
collection = new TCollection();
}
public void Store(T obj)
{
collection.Add(obj);
}
public TCollection Items
{
get { return collection; }
}
}
用法:
MyClass<List<string>, string> myclass = new MyClass<List<string>, string>();
myclass.Store("First element");
myclass.Store("Second element");
myclass.Items.ForEach(s => Console.WriteLine(s));
编辑: 当 T 变得越来越复杂时,你可能想看看 using 指令,你可以(错误地)将其用作 typedef。
using HugeType = System.Collections.Generic.Dictionary<int, string>; // Example 'typedef'
...
//Create class, note the 'typedef' HugeType
MyClass<List<HugeType>, HugeType> myclass = new MyClass<List<HugeType>, HugeType>();
//Fill it
HugeType hugeType1 = new HugeType();
hugeType1.Add(1, "First");
hugeType1.Add(2, "Second");
HugeType hugeType2 = new HugeType();
hugeType1.Add(3, "Third");
hugeType1.Add(4, "Fourth");
myclass.Store(hugeType1);
myclass.Store(hugeType2);
//Show it's values.
myclass.Items.ForEach(element => element.Values.ToList().ForEach(val => Console.WriteLine(val)));
评论
MyClass<List<string, string>
MyClass<Dictionary< foo, Dictionary<bar, KeyValuePair<baz, List<wrgl>>>>, <bar, KeyValuePair<baz, List<wrgl>>>>
typedef
typedef
typedef
using
是否有任何公开类型的公共成员?TCollection
如果有任何这样的成员,你是否获得了公开可以公开的直接类型的任何价值?TCollection
ICollection<T>
您的客户端应该实现该接口,因此它不会真正影响您的对象;您只会调用该接口,而不是其特定类型。因此,对象只需要知道集合中存储的元素类型。ICollection<T>
在这个前提下,类可以这样写:
public class MyClass<T>
{
public MyClass(ICollection<T> collection)
{
/* store reference to collection */
}
// ...
public void store(T obj)
{
/* put obj into collection */
}
// ...
}
评论
TCollection
ICollection<T>
上一个:临时更改变量的值
评论
class MyClass { private ICollection<T> _data; public MyClass(ICollection<T> collection) { _data = collection; } }
Dictionary<K,V>
List<KeyValuePair<K,V>>