0

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

让我们有这些类:

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

我的情况是:

  • 我有一组已经初始化的香蕉和苹果,比如这两个(但我可以使用不同的):

    Fruit[] myFruits = new Fruit[2]
    {
        new Banana(),
        new Apple()
    };
    
  • 我有一组图片,比如这两个:

    Picture[] myPictures = new Picture[2]
    {
        new FruitPicture<Banana>(),
        new FruitPicture<Apple>(),
    };
    

现在,我试图做一件非常简单的事情,但以一种通用的方式,这意味着我想避免任何开关/ifs,每次找到新水果时我都必须更改代码并且新的 FruitPicture 可能会出现在集合中 =>我想.AddFruit()从我的收藏中选择正确类型的 FruitPicture。我几乎可以更改任何逻辑,但我想保留通用的 FruitPicture 类。

我得到的最接近的是:

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

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

4

1 回答 1

0

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

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

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是必需的,因为 is 的类型fruit不是Fruit传递给 any 的有效类型SetFruit。它必须是动态的,因为 is 的静态编译时类型ChangeTypeobject它也不是 any 的有效类型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);
    }
}
于 2018-10-22T22:02:16.887 回答