[英]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.