C # covariance

In my C # code, I came across some interesting covariance problem.

I have a common Matrix<T> class, and it was created, for example, Matrix<int> , Matrix<object> and Matrix<Apple> .

For my business logic, I wrapped them in a generic Wrapper<T> . This Wrapper does not implement the common INonGenericWrapper interface. So I have a Wrapper<int> , Wrapper<object> and Wrapper<Apple> .

My problem: I would like to define a container for all these 3 Wrapper s. I cannot say List<Wrapper<object>> because I cannot insert a Wrapper<int> into this collection. I can’t even tell List<INonGenericWrapper> , because inside my foreach I would like to access the general Matrix<T> parameter.

Cheese: these Wrappers will be (de-) serialized with a specific type: MySerializer<Wrapper<Apple>>.Serialize(_myInstanceOfWrappedApple) .

I think it is clear that I would like to avoid the huge typeof switches when serializing ..

What are my possible workarounds? I'm a little stuck.

Thanks in advance,

+2
source share
2 answers

I recently encountered this restriction, and I implemented the Visitor Template option (maybe this is an abuse). But it helped me solve the problem.

I am not an architect, just a developer. So forgive me if I abuse the design pattern, but this will definitely help.

With the information I provided, I created bullying of your classes and the visitor template applied as follows.

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

How to use:

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

All you have to do is create a new visitor for each operation you need to perform.

Here is a demo that outputs

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

You said you want to embed data in a collection based on a covariantly open type. It is simply not possible. For a type that must be covariant, it does not need to disclose any means of inserting data. The type must be contravariant to support this, but if the type is contravariant, then it cannot expose the information in the covariant estate.

In short, this is impossible, and not just impossible due to the fact that C # as a language implemented, but impossible at a conceptual level. It is not possible to implement a statically typed solution to this problem in any conceivable language.

0
source

Source: https://habr.com/ru/post/1240466/


All Articles