Generics: access to new members, not hidden members

I have a problem with generics and new members. I wrote a generic class that works with an object of type ObjectA. ObjectB comes from ObjectA and hides several members of ObjectA. When I set the ObjectB type as a type parameter for a general class, I would expect that when I call any of the elements hidden by ObjectB, I would call an implementation of ObjectB. However, the CLR still calls hidden elements (an ObjectA implementation). This seems counterintuitive because I explicitly provided the ObjectB type to the generic class. Is this a problem with the generics themselves, or am I doing something wrong?

Edit: Unfortunately, I do not have access to the source code of ObjectA, and the member I want to override is not virtual. If I had access to the source code of ObjectA, I would make it a virtual member, but since I cannot do this, my only option for โ€œredefiningโ€ a member is through a โ€œnewโ€ keyword.

 class GenericClass<T> where T : ObjectA { public void DoWork(T item) { // When type parameter 'T' is ObjectB, should get ObjectB implementation item.Invoke(); } } class ObjectA { public void Invoke() { // A implementation... } } class ObjectB : ObjectA { public new void Invoke() { // B implementation... } } static void Main() { GenericClass<ObjectB> genericClass = new GenericClass<ObjectB>(); ObjectB objectB = new ObjectB(); genericClass.DoWork(objectB); } 

code>

+1
source share
3 answers

Not. Calls generated by the compiler relate to members that it knows at compile time. That members exposed by ObjectA .

Any reason you don't use regular inheritance with virtual / overridden methods?

Here is another example of the same type, by the way - the overloaded == operator for strings is not used, although T is string in the Foo call:

 using System; class Test { static bool Foo<T>(T first, T second) where T : class { return first == second; } static void Main() { string x = "hello"; string y = new string(x.ToCharArray()); Console.WriteLine(Foo(x, y)); } } 
+7
source

This may not be the answer to your question, but I do not see the point in your approach (perhaps because I see only a simplified example).

I would suggest using the following approach:

 class ObjectA { public virtual void Invoke() { // do some work } } class ObjectB : ObjectA { public override void Invoke() { // do some other work } } class GenericNotNeededClass { public void DoWork(ObjectA item) { item.Invoke(); } } static void Main() { GenericNotNeededClass nonGenericClass = new GenericNotNeededClass(); ObjectB objectB = new ObjectB(); nonGenericClass.DoWork(objectB); } 

I would believe that the code does what you are looking for based on your sample code.

0
source

You define a type T of type ObjectA for your generic. If Invoke () was virtual, it would work the way you think, but since it is not, your common call invokes the ObjectA implementation, because that is what T. defines.

There is no virtual method table entry to indicate an ObjectB implementation for Invoke (), so this may cause a call at runtime. If it were a virtual method, VMT would have the address of the method, and it will act the way you think it will.

0
source

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


All Articles