简体   繁体   English

无法将C#通用对象添加到该通用类型的列表中

[英]C# generic object cannot be added to list of that generic type

Sorry if question name wasn't that explicit, but I couln't find a better one... 抱歉,问题名称不是那么明确,但是我找不到更好的问题...

Here's my problem : 这是我的问题:

I have a class : 我有一堂课:

public class WatchableVariable<T>{
  ...
}

A Container Class : 容器类:

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);
  }

  ...
}

And have a strange error : 并有一个奇怪的错误:

在此处输入图片说明

Which, IMO, should work since i'm applying a "IComparable" constraint on my generic type. IMO,这应该起作用,因为我在我的通用类型上应用了“ IComparable”约束。

could someone point me out where I might have messed up ? 有人可以指出我可能会搞砸的地方吗?

EDIT : I already tried to implement IComparable on Class WatchableVariable which resulted in the exact same error :/ 编辑 :我已经尝试在Class WatchableVariable上实现IComparable,导致完全相同的错误:/

public class WatchableVariable<T> : ObservableObject where T : IComparable
  { ... }

EDIT 2 : While trying to implement the solution proposed by canton7, I realized I may be blocked. 编辑2 :在尝试实施canton7提出的解决方案时,我意识到我可能会被阻止。

Here's the interface I created : 这是我创建的界面:

public interface IWatchableVariable<out T>
{
  T Variable { get; set; }
}

Here's what I'm trying to achieve : 这是我要实现的目标:

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");

Does this make things clearer ? 这使事情更清楚了吗?

Your collection is a List<WatchableVariable<IComparable>> . 您的集合是List<WatchableVariable<IComparable>> You're trying to add a WatchableVariable<T> to it. 您正在尝试向其中添加WatchableVariable<T>

This is not allowed, because of the rules of generic variance. 由于通用差异规则,这是不允许的。 Let's pretend that your WatchableVariable<T> class defined this method: 假设您的WatchableVariable<T>类定义了此方法:

public class WatchableVariable<T>
{
    public void Set(T value);
}

If you've got a WatchableVariable<Foo> , you can call watchableVariable.Set(new Foo()) , but not watchableVariable.Set((IComparable)foo) . 如果您有WatchableVariable<Foo> ,则可以调用WatchableVariable<Foo> watchableVariable.Set(new Foo()) ,但不能调用WatchableVariable<Foo> watchableVariable.Set((IComparable)foo) That makes sense. 那讲得通。

Take that to your situation, and someone could call Add<Foo>("") , so Watchables contains a WatchableVariable<Foo> . 考虑到您的情况,有人可以调用Add<Foo>("") ,因此Watchables包含一个WatchableVariable<Foo> They then access Watchables[0] , which gives them a WatchableVariable<IComparable> , and call Set((IComparable)bar) . 然后,他们访问Watchables[0] ,这为它们提供了WatchableVariable<IComparable> ,并调用Set((IComparable)bar) This would be unsafe, as we previously said that a WatchableVariable<Foo> 's Set(T value) method will only accept a Foo , but we've just given it any old IComparable ! 这将是不安全的,因为我们之前曾说过WatchableVariable<Foo>Set(T value)方法将只接受Foo ,但是我们已经给了它任何旧的IComparable

The way around this is using covariance, which is only available on interfaces. 解决此问题的方法是使用协方差,仅在接口上可用。

First, we declare a generic interface, and we promise that you can only ever take T 's out of it, and never put them in, using out T : 首先,我们声明一个通用接口,并保证您只能从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>
{
    // ...
}

Then you can write: 然后您可以编写:

private List<IWatchableVariable<IComparable>> Watchables;

And everything will work. 一切都会正常。

(A similar thing is available using contravariance and in T , but that isn't applicable to your situation). in T使用convariance和in T可以得到类似的结果,但这不适用于您的情况)。


In response to your Edit 2 回应您的Edit 2

Your edit contains the comment 您的修改包含评论

// Variable would be a property of type T (which would be double in this case)

That's a run-time assertion. 那是一个运行时断言。 You will have to define your interface like this: 您将必须这样定义您的界面:

public interface IWatchableVariable<out T>
{
    object Variable { get; set; }
}

Since Variable isn't of type T , this is allowed. 由于Variable不是T类型,因此可以使用。 Then your WatchableVariable<T> class will have to do a run-time cast, to make sure that Variable was set to a compatible type. 然后,您的WatchableVariable<T>类将必须进行运行时强制转换,以确保将Variable设置为兼容类型。 You can use an explicit interface implementation to make this a bit neater. 您可以使用一个显式的接口实现来使其更加整洁。

public class WatchableVariable<T>
{
    public T Variable { get; set; }

    object IWatchableVariable<T>.Variable
    {
        get => Variable;
        set => Variable = (T)value;
    }
}

You can make this slightly neater by doing something like: 您可以通过执行以下操作使此内容更加整洁:

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;
    }
}

I don't know what are you trying to achieve, but to make that work you should: declare your type with an IComparable constraint. 我不知道您要达到什么目的,但是要完成该工作,您应该:使用IComparable约束声明您的类型。

public class WatchableVariable<T> where T : IComparable
{
    public WatchableVariable(string name) { }
}

Then make your second class generic with the same constraint. 然后使第二类具有相同的约束。

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