将类型的 object 添加到适合泛型类型的 object 的多功能解决方案

Versatile solution for adding object of a type to an object of fitting generic type

我觉得接口(反?)方差是答案,但找不到正确的解决方案。

让我们有这些 classes:

public abstract class Fruit { }
public class Banana : Fruit { }
public class Apple : Fruit { }

public abstract class Picture { }
public class FruitPicture<T> : Picture, Contravariant<T>, Covariant<T> where T : Fruit
{
    T myFruit = null;

    public Type GetFruitType() { return typeof(T); }

    public void AddFruit(T fruit) { this.myFruit = fruit; }
}

public interface Contravariant<in T> { void AddFruit(T model); }
public interface Covariant<out T> { Type GetFruitType(); }

我的情况是:

现在,我试图做一件非常简单的事情,但是以一种通用的方式,这意味着我想避免任何 switches/ifs 每次发现新水果和新 FruitPicture 时我都必须更改代码的情况可能会出现在 collection => 我想 .AddFruit() 从我的 collection 到正确类型的 FruitPicture。我几乎可以更改任何逻辑,但我想保留通用 FruitPicture class.

最接近的是:

foreach(Picture curPicture in myPictures)
{
    foreach (Fruit curFruit in myFruits)
    {
        Covariant<Fruit> fruitType = (Covariant<Fruit>)curPicture;
        if (curFruit.GetType() == fruitType.GetFruitType())
        {
            // what now?
        }
    }
}

谢谢先生。双向飞碟(开玩笑;有点)

由于你遇到的问题是你想进行编译时类型安全,但直到 运行 时间你才知道类型,你可以推迟到 运行 后再做决定- 使用 dynamic 的时间。我不一定推荐这个,只是说它会起作用。

我将 Covariant 接口更改为不需要通用,因为它没有使用类型参数。我将 AddFruit 重命名为 SetFruit 因为它没有添加任何东西,而是替换了

foreach (var fruit in myFruits) {
    foreach (var picture in myPictures) {
        if (picture is Covariant cov) {
            if (cov.GetFruitType() == fruit.GetType())
                ((dynamic)picture).SetFruit(Convert.ChangeType((dynamic)fruit, cov.GetFruitType()));
        }
    }
}

需要 (dynamic) ChangeType,因为 fruit 的类型是 Fruit,这不是传递给任何 SetFruit 的有效类型].它必须是动态的,因为 ChangeType 的静态编译时类型是 object,这对于任何 SetFruit.

也是无效的类型

或者,如果您将决定推入 FruitPicture 会怎么样?

public interface Covariant {
    void SetCompatibleFruit(Fruit f);
}

public class FruitPicture<T> : Picture, Covariant where T : Fruit {
    T myFruit = null;

    public void SetCompatibleFruit(Fruit f) {
        if (f is T tf)
            this.myFruit = tf;
    }
}

然后请每个 Covariant picture 设置 fruit 如果可以:

foreach (var fruit in myFruits) {
    foreach (var picture in myPictures) {
        if (picture is Covariant cov)
            cov.SetCompatibleFruit(fruit);
    }
}