[英]C# generic object cannot be added to list of that generic type
抱歉,问题名称不是那么明确,但是我找不到更好的问题...
这是我的问题:
我有一堂课:
public class WatchableVariable<T>{
...
}
容器类:
public class CommonWatchableVariableContainer
{
private List<WatchableVariable<IComparable>> Watchables;
...
public void Add<T>(string name) where T : IComparable
{
WatchableVariable<T> test = new WatchableVariable<T>(name);
Watchables.Add(test);
}
...
}
并有一个奇怪的错误:
IMO,这应该起作用,因为我在我的通用类型上应用了“ IComparable”约束。
有人可以指出我可能会搞砸的地方吗?
编辑 :我已经尝试在Class WatchableVariable上实现IComparable,导致完全相同的错误:/
public class WatchableVariable<T> : ObservableObject where T : IComparable
{ ... }
编辑2 :在尝试实施canton7提出的解决方案时,我意识到我可能会被阻止。
这是我创建的界面:
public interface IWatchableVariable<out T>
{
T Variable { get; set; }
}
这是我要实现的目标:
double dVar1 = process();
double dVar2 = process();
double dVar3 = process();
bool bVar1 = process();
CommonWatchableVariableContainer container = new CommonWatchableVariableContainer ();
container.Add<bool>("myTrackedVariable_1");
container.Add<double>("myTrackedVariable_2");
container["myTrackedVariable_1"].Variable = dVar1; //Variable would be a property of type T (which would be double in this case)
container["myTrackedVariable_2"].Variable = bVar1;
foreach(IWatchableVariable WV in container){
process(WV);
}
container.Remove("myTrackedVariable_1");
这使事情更清楚了吗?
您的集合是List<WatchableVariable<IComparable>>
。 您正在尝试向其中添加WatchableVariable<T>
。
由于通用差异规则,这是不允许的。 假设您的WatchableVariable<T>
类定义了此方法:
public class WatchableVariable<T>
{
public void Set(T value);
}
如果您有WatchableVariable<Foo>
,则可以调用WatchableVariable<Foo>
watchableVariable.Set(new Foo())
,但不能调用WatchableVariable<Foo>
watchableVariable.Set((IComparable)foo)
。 那讲得通。
考虑到您的情况,有人可以调用Add<Foo>("")
,因此Watchables
包含一个WatchableVariable<Foo>
。 然后,他们访问Watchables[0]
,这为它们提供了WatchableVariable<IComparable>
,并调用Set((IComparable)bar)
。 这将是不安全的,因为我们之前曾说过WatchableVariable<Foo>
的Set(T value)
方法将只接受Foo
,但是我们已经给了它任何旧的IComparable
!
解决此问题的方法是使用协方差,仅在接口上可用。
首先,我们声明一个通用接口,并保证您只能从T
取出T
,而永远不会使用out T
来放入它们:
public interface IWatchableVariable<out T>
{
// The compiler stops you from defining any methods which accept a T
}
public class WatchableVariable<T> : IWatchableVariable<T>
{
// ...
}
然后您可以编写:
private List<IWatchableVariable<IComparable>> Watchables;
一切都会正常。
( in T
使用convariance和in T
可以得到类似的结果,但这不适用于您的情况)。
回应您的Edit 2
您的修改包含评论
// Variable would be a property of type T (which would be double in this case)
那是一个运行时断言。 您将必须这样定义您的界面:
public interface IWatchableVariable<out T>
{
object Variable { get; set; }
}
由于Variable
不是T
类型,因此可以使用。 然后,您的WatchableVariable<T>
类将必须进行运行时强制转换,以确保将Variable
设置为兼容类型。 您可以使用一个显式的接口实现来使其更加整洁。
public class WatchableVariable<T>
{
public T Variable { get; set; }
object IWatchableVariable<T>.Variable
{
get => Variable;
set => Variable = (T)value;
}
}
您可以通过执行以下操作使此内容更加整洁:
public interface IWatchableVariable<out T>
{
T Variable { get; }
void SetVariable(object value);
}
public class WatchableVariable<T> : IWatchableVariable<T>
{
public T Variable { get; set; }
public void SetVariable(object value)
{
Variable = (T)value;
}
}
我不知道您要达到什么目的,但是要完成该工作,您应该:使用IComparable
约束声明您的类型。
public class WatchableVariable<T> where T : IComparable
{
public WatchableVariable(string name) { }
}
然后使第二类具有相同的约束。
public class CommonWatchableVariableContainer<T> where T : IComparable
{
private List<WatchableVariable<T>> Watchables;
public void Add(string name)
{
var test = new WatchableVariable<T>(name);
Watchables.Add(test);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.