与C#的协方差

本文关键字:方差 | 更新日期: 2023-09-27 17:59:54

我在c#代码中遇到了一些有趣的协方差问题。

我有一个通用的Matrix<T>类,它已经被实例化,例如Matrix<int>Matrix<object>Matrix<Apple>

对于我的业务逻辑,我已经将它们封装到一个通用的Wrapper<T>中。这个包装器实现了非通用的INonGenericWrapper接口。所以,我有Wrapper<int>Wrapper<object>Wrapper<Apple>

我的问题是:我想为所有这3个Wrapper s定义一个容器。我不能说List<Wrapper<object>>,因为我不能将Wrapper<int>插入到这个集合中。我甚至不能说List<INonGenericWrapper>,因为在我的foreach中,我想访问通用的Matrix<T>参数。

Cheesy部分:这个Wrappers将被(反)序列化为明确的类型:MySerializer<Wrapper<Apple>>.Serialize(_myInstanceOfWrappedApple)

我想很明显,在序列化时,我希望避免typeof的巨大切换。。

我可能的解决方案是什么我有点困了。

提前感谢,

与C#的协方差

最近我遇到了这样的限制,我实现了访问者模式的变体(可能是滥用它)。但这帮助我解决了问题。

我不是建筑师,只是一个开发人员。所以,如果我滥用设计模式,请原谅我,但这肯定会有所帮助。

根据提供的信息,我创建了您的类的mock,并应用了如下访问者模式。

public class Matrix<T>
{
    public T Obj { get; set; }
}
public interface INonGenericWrapper
{
    void Wrap();
    void Accept(IVisitor visitor);
}
public class Wrapper<T> : INonGenericWrapper
{
    public Matrix<T> Matrix { get; private set; }
    public void Wrap()
    {
        //Your domain specific method
    }
    public void Accept(IVisitor visitor)
    {
        visitor.Visit(this);
    }
}
public interface IVisitor
{
    void Visit<T>(T element);
}
public class SerializationVisitor : IVisitor
{
    public void Visit<T>(T element)
    {
        new Serializer<T>().Serialize(element);
    }
}
public class Serializer<T>
{
    public Stream Serialize(T objectToSerialize)
    {
        Console.WriteLine("Serializing {0}", objectToSerialize);
        //Your serialization logic here
        return null;
    }
}

如何使用:

List<INonGenericWrapper> wrappers = new List<INonGenericWrapper>();
wrappers.Add(new Wrapper<object>());
wrappers.Add(new Wrapper<string>());
wrappers.Add(new Wrapper<int>());
var visitor = new SerializationVisitor();//Create the operation you need to apply
foreach (var wrapper in wrappers)
{
    wrapper.Accept(visitor);
}

你所要做的就是为你需要执行的每个操作创建一个新的访问者。

这是输出的演示

Serializing Wrapper`1[System.Object]
Serializing Wrapper`1[System.String]
Serializing Wrapper`1[System.Int32]

您已经说过,您希望能够根据协变公开的类型将数据插入到集合中。这根本不可能。对于协变类型,它不需要公开任何插入数据的方法。类型需要是反变量才能支持这一点,但如果类型是反变量,那么它就不能在协变庄园中公开信息。

简而言之,这是不可能的,不仅因为C#作为一种语言已经实现了什么,而且在概念层面上也是不可能的。不可能用任何可以想象的语言来实现这个问题的静态类型的解决方案。