将类型的 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(); }
我的情况是:
我有一个 collection 的 Bananas 和 Apples 已经初始化,例如这两个(但我可以使用不同的):
Fruit[] myFruits = new Fruit[2]
{
new Banana(),
new Apple()
};
我有collection张图片,比如这两张:
Picture[] myPictures = new Picture[2]
{
new FruitPicture<Banana>(),
new FruitPicture<Apple>(),
};
现在,我试图做一件非常简单的事情,但是以一种通用的方式,这意味着我想避免任何 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);
}
}
我觉得接口(反?)方差是答案,但找不到正确的解决方案。
让我们有这些 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(); }
我的情况是:
我有一个 collection 的 Bananas 和 Apples 已经初始化,例如这两个(但我可以使用不同的):
Fruit[] myFruits = new Fruit[2] { new Banana(), new Apple() };
我有collection张图片,比如这两张:
Picture[] myPictures = new Picture[2] { new FruitPicture<Banana>(), new FruitPicture<Apple>(), };
现在,我试图做一件非常简单的事情,但是以一种通用的方式,这意味着我想避免任何 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);
}
}