簡體   English   中英

無法將C#通用對象添加到該通用類型的列表中

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM