C # general explicit disclaimer

I have some problems with the following code snippet. I would like to allocate a string for an object, but this works fine, however, if this object is part of a generic class, it crashes with the following exception: "You cannot use an object of type" System.String "to enter" test.B ". Even if I overloaded the method.

using System; using System.Collections.Generic; namespace test { class Program { static void Main(string [] args) { // These two cast perfectly fine. B x = (B) "abc"; C y = (C) "def"; A <B> a = new A<B>(); ab(); A <C> b = new A<C>(); bb(); } } class A<T> { public List <T> a = new List<T>(); public void b() { // Unable to cast object of type 'System.String' to type 'test.B' this.a.Add ((T) (object) "abc"); this.a.Add ((T) (object) "def"); this.a.Add ((T) (object) "ghi"); } } class B { public string b; public static explicit operator B(string a) { B x = new B(); xb = a; return x; } } class C { public string c; public static explicit operator C(string a) { C x = new C(); xc = a; return x; } } } 

It would be great if someone could explain to me why this is not correctly discarded.

thanks

+6
source share
4 answers

Conversion operators apply only when the type is known statically; after all, generic methods should use the exact IL for each T - so it cannot invoke your statement in some cases and type checking in others.

Also, since you have a distinctly different object , it will never be; The listing from object always a simple delete check or type.

It would be a bad fix (and I don't like it):

  this.a.Add((T)(dynamic)"abc"); this.a.Add((T)(dynamic)"def"); this.a.Add((T)(dynamic)"ghi"); 

which discards permission at runtime. It works, but after that I had to wash my eyes. In general, though: operators and generics do not play well - like this: try not to use this combination in your API. I really would not use it, personally!

+8
source

The compiler does not have knowledge at compile time if the generic parameter has an explicit listing that you use.

You can enter the interface, although you put a restriction on the general parameter

+2
source

Because T for A<T> does not know about explicit cast operations for B or C

+1
source

You added (an object) to make the compiler stop telling you that you are doing it wrong. This worked, the compiler can no longer complain because it does not allow type checking. And casting from object to T can really work as much as possible.

What you did not expect, however, is that explicit conversion operators are C # language. Only the compiler knows which method to execute when such a cast is applied. This is not a CLR function; the runtime does not go hunting and collecting in order to try to find an applicable method for conversion. The C # compiler is otherwise powerless to use any of the operators that you provided at compile time, it does not know the type T.

The problem is that the compiler no longer helps when casting is done. Kaboom.

Having generic types used at runtime instead of compile time is a .NET function, the general term is β€œreified generics”. In contrast to "type erasure," how generic tools are implemented in Java and C ++. The problem with type-erasing is that all information about type-type arguments is lost after compiling the code, the general type cannot be used in another language, and Reflection does not work. The problem with generic generics is that operations that cannot be applied universally to any type cannot be used. Like the operator + (). And like that.

+1
source

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


All Articles