我需要编写一个泛型类,其中type参数必须是实现ICollection<T>
的东西。在MyClass
内,我需要收藏品的项目类型(在标有???
的代码段中)。
class MyClass<TCollection> where TCollection : ICollection<???>
{
// ...
public void store(??? obj) { /* put obj into collection */ }
// ...
}
该集合通常实际上是一本字典。有时,它会像列表一样简单。
我确切知道如何在C ++中执行此操作。我怎么做这个是C#?
答案 0 :(得分:5)
嗯,您通常使用其他类型参数执行此操作:
class MyClass<TCollection, TElement> where TCollection : ICollection<TElement>
{
// ...
public void store(TElement obj) { }
// ...
}
在这种情况下你真的需要TCollection
吗?你能用TElement
吗?
答案 1 :(得分:3)
最简单的要做的事情就是只指定元素类型,并在任何需要的地方硬编码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;
}
}
}
我建议您将集合实例传递给构造函数,而不是在内部创建一个。它使类更简单,更“通用”(借口双关语),并允许您使用非默认构造函数构造集合实例,例如带有非默认比较器的字典。
重新编辑(第三次尝试):使用类继承和命名空间别名来模拟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
不能是派生类,否则编译器不会将其识别为另一个的元素。
答案 2 :(得分:2)
这对我有用:
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 directive,你可以(误)将它用作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)));
答案 3 :(得分:1)
你不能这样做吗?:
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);
}
}
答案 4 :(得分:1)
是否有公开成员公开类型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 */
}
// ...
}