我遇到的问题是如何让我的SetContainer
更通用,以包含任何扩展CompoundValue
的类型。
这就是我尝试过的MapContainer<string, SetContainer<CompoundValue>>
。
但我在state["a"] = new SetContainer<A>
上收到错误,说A类型无法显式转换为CompoundValue。
我已经提供了一个相关示例,显示了下面的问题。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Microsoft.Modeling; // SetContainer and MapContainer
namespace SGSN
{
class ControlState
{
MapContainer<string, SetContainer<CompoundValue>> state;
ControlState()
{
state = new MapContainer<string, SetContainer<CompoundValue>>();
state["a"] = new SetContainer<A>(); //ERROR
state["b"] = new SetContainer<B>(); //ERROR
state["c"] = new SetContainer<C>(); //ERROR
state["d"] = new SetContainer<D>(); //ERROR
}
}
class A: CompoundValue
{
internal string a1;
internal string a2;
internal string a3;
internal string a4;
internal string a5;
internal string a6;
internal A(string a1, string a2, string a3,
string a4, string a5, string a6)
{
this.a1= a1;
this.a2= a2;
this.a3= a3;
this.a4= a4;
this.a5= a5;
this.a6= a6;
}
}
class B: CompoundValue
{
internal string b1;
internal string b2;
internal string b3;
internal B(string b1, string b2, string b3)
{
this.b1= b1;
this.b2= b2;
this.b3= b3;
}
}
class C: CompoundValue
{
internal string c1;
internal string c2;
internal string c3;
internal string c4;
internal string c5;
internal string c6;
internal string c7;
internal string c8;
internal C(string c1, string c2, string c3,
string c4, string c5, string c6, string c7, string c8)
{
this.c1 = c1;
this.c2= c2;
this.c3= c3;
this.c4= c4;
this.c5 = c5;
this.c6= c6;
this.c7= c7;
this.c8= c8;
}
}
class D: CompoundValue
{
internal string d1;
internal string d2;
internal string d3;
internal D(string d1, string d2, string d3)
{
this.d1= d1;
this.d2= d2;
this.d3= d3;
}
}
}
答案 0 :(得分:3)
您可以像这样声明集合容器:
public class SetContainer<T>
where T : CompoundValue
{ ... }
然而,这并没有解决问题。为什么?您可以使用源自T
(或CompoundValue
本身)的CompoundValue
;但是,即使SetContainer<A>
来自SetContainer<CompoundValue>
,这也不会使A
成为CompoundValue
的后代。即,构造的泛型类型不接管其泛型类型参数的继承关系。因此,MapContainer<string, SetContainer<CompoundValue>>
不接受SetContainer<A>
作为值!
让我们举一个更简单的例子,让我们宣布一个这样的列表
List<CompoundValue> list = new List<A>(); // Not possible!
这是不可能的,但我们假设它是。现在让我们在列表中添加值:
list.Add(new CompoundValue()); // Error!
list.Add(new A()); // OK
list.Add(new B()); // Error!
这似乎是可能的,因为A
和B
继承自CompoundValue
。但请记住,该列表实际上是List<A>
,此列表需要存储A
或A
的后代。 CompoundValue
和B
都不是A
s!
答案 1 :(得分:1)
您可以从SetContainer派生并在派生类中定义约束。而不是使用SetContainer,您可以使用带有约束的派生类。
首先,您将从SetContainer定义您的派生:
public class YourContainer<T> : SetContainer<T> where T : CompoundValue
{
// no code needed here
}
之后,您将在任何地方使用容器而不是SetContainer:
MapContainer<string, YourContainer<CompoundValue>> state;
现在,您可以使用容器初始化您的成员:
state = new MapContainer<string, YourContainer<CompoundValue>>();
而不是添加SetContainer,您现在可以添加已定义类型约束的Container。
state["a"] = new YourContainer<A>();
答案 2 :(得分:0)
你想做什么是不可能的。即使B类来自A,也不意味着Foo&lt; B&gt;与Foo&lt; A&gt;兼容。
尝试编译:
class Foo<T> {}
class Bar {}
class Baz : Bar {}
void Main()
{
var list = new List<Foo<Bar>>();
list.Add(new Foo<Baz>());
}
您需要更改设计。尝试使用包装类。
class Foo<T>
{
public T Item { get; set; }
public Foo(T t)
{
Item = t;
}
}
class Bar
{
public override string ToString()
{
return "Bar";
}
}
class Baz : Bar
{
public override string ToString()
{
return "Baz";
}
}
class BarHolder
{
public Bar BarItem { get; set; }
public BarHolder(Bar bar)
{
BarItem = bar;
}
}
void Main()
{
var wrappedBar = new BarHolder(new Bar());
var wrappedBaz = new BarHolder(new Baz());
var barList = new List<Foo<BarHolder>>();
barList.Add(new Foo<BarHolder>(wrappedBar));
barList.Add(new Foo<BarHolder>(wrappedBaz));
foreach (var obj in barList)
{
Console.WriteLine(obj.Item.BarItem);
}
}