How to use method hiding (new) with generic constrained class - c#

I have a container class that has a generic parameter which is constrained to some base class. The type supplied to the generic is a sub of the base class constraint. The sub class uses method hiding (new) to change the behavior of a method from the base class (no, I can't make it virtual as it is not my code). My problem is that the 'new' methods do not get called, the compiler seems to consider the supplied type to be the base class, not the sub, as if I had upcast it to the base.
Clearly I am misunderstanding something fundamental here. I thought that the generic where T: xxx was a constraint, not an upcast type.
This sample code basically demonstrates what I'm talking about.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericPartialTest
{
class ContextBase
{
public string GetValue()
{
return "I am Context Base: " + this.GetType().Name;
}
public string GetOtherValue()
{
return "I am Context Base: " + this.GetType().Name;
}
}
partial class ContextSub : ContextBase
{
public new string GetValue()
{
return "I am Context Sub: " + this.GetType().Name;
}
}
partial class ContextSub
{
public new string GetOtherValue()
{
return "I am Context Sub: " + this.GetType().Name;
}
}
class Container<T> where T: ContextBase, new()
{
private T _context = new T();
public string GetValue()
{
return this._context.GetValue();
}
public string GetOtherValue()
{
return this._context.GetOtherValue();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Simple");
ContextBase myBase = new ContextBase();
ContextSub mySub = new ContextSub();
Console.WriteLine(myBase.GetValue());
Console.WriteLine(myBase.GetOtherValue());
Console.WriteLine(mySub.GetValue());
Console.WriteLine(mySub.GetOtherValue());
Console.WriteLine("Generic Container");
Container<ContextBase> myContainerBase = new Container<ContextBase>();
Container<ContextSub> myContainerSub = new Container<ContextSub>();
Console.WriteLine(myContainerBase.GetValue());
Console.WriteLine(myContainerBase.GetOtherValue());
Console.WriteLine(myContainerSub.GetValue());
Console.WriteLine(myContainerSub.GetOtherValue());
Console.ReadKey();
}
}
}
Edit:
I guess my confusion comes from that one can do this
class SomeClass<T> where T: AnotherType, new()
{
T foo = new T();
}
And I expected T to be T even though I understand the compiler would view T as having AnotherType's interface. I assumed the typing of T would happen at run-time even if the interface of T was set at compile time. The T foo declaration seems misleading here because it is really doing
AnotherType foo = new T();
Once I understand that it is not really declaring foo as type T, it is understandable why the new method hiding wouldn't work.
And that's all I have to say about that.

Methods declared new have no relation (from the compiler's perspective) to methods with the same name/signature in the base class. This is simply the compiler's way of allowing you to define different methods in derived classes that share a signature with a method in their base class heirarchy.
Now, with regard to your specific case, realize that generics have to compile to a single set of bytecode regardless of the types that are supplied as generic parameters. As a result, the compiler only knows about the method and properties that are defined on the generic type T - that would be the base type you specify in the generic constraint. The compiler knows nothing about the new methods in your derived type, even if you create an instance of a generic type with the derived type as the parameter. Therefore calls in the generic class will always go to the methods of the base type.
There's a lot of confusion about new/virtual/override; take a look at this SO question - Jason and Eric's answers are excellent. Jon Skeet's answer to a similar question may also help you understand why your implementation behaves the way it does.
There are two possible ways for you to work around this issue:
Perform a conditional cast (based on runtime type information) to the derived type (or an interface) in your generic class. This breaks encapsulation and adds undesirable coupling. It's also fragile if implemented poorly.
Define an interface that you use in your generic constraint that exposes the methods you care about. This may not be possible if the code you are deriving from is not something you can change.

Add another layer - inherit your generic not from your third party class but from a new class which in turn inherits from the third party. In this new class you can define the method in question as new virtual. If all your code never references the third part class directly, it should work

Related

Why calling method on interface uses base implementation instead of override?

I have a problem with my code.
I would expect that since I'm constructing the Implementation object; every time I call Method() I'd use actual Implementation.Method() and not it's abstract's Base.Method(). It does not seem reasonable that I have to downcast to actual implementer or specify interface explicitly (So interfaces are not transitive in C#? I will call the "first proper instance of interface implementer" and not my class?)
I have a structure similar to this (simplified for clarity):
https://dotnetfiddle.net/oYVlQO
using System;
public interface IBase
{
string Method();
}
public abstract class Base : IBase
{
public string Method() { return "Sample"; }
}
public class Implementation : Base // if I add ", IBase" to this it works as expected, but why?
{
new public string Method() { return "Overriden"; }
}
public class Program
{
// and it's used like so...
public static void Main()
{
IBase b = new Implementation();
//Implementation b = new Implementation(); // It works as expected, always using Implementation.Method();
Console.WriteLine(b.Method()); // Produces "Sample", so Base.Method(). Why not implementation?
Console.WriteLine(((Implementation) b).Method()); // Produces "Overriden", so Implementation.Method(); Since when I have to downcast to use overriden method!?
}
}
}
I'm really scratching my head over this; Especially that the same code in Java works "as I would expect" https://repl.it/repls/VitalSpiritedWebpage
I've tried to find it in the c# specs to no avail, maybe I do not have the proper keywords...
In cause of the question, which is:
Why is it that way?
My answer:
Because you don’t override the method but hide it.
The interface is implemented by the baseclass, so the Method is called on the base-class.
To answer the question, which isn’t asked:
How would it work?
Answer:
using System;
public interface IBase
{
string Method();
}
public abstract class Base : IBase
{
public virtual string Method() { return "Sample"; }
}
public class Implementation : Base
{
public override string Method() { return "Overriden"; }
}
You may want to take a look at the part of the C# spec that deals with interface re-implementation.
When you access a member through the interface, it begins its lookup at the most derived type that explicitly implements that interface. In your example, the most derived type is Base and so it calls the method that's present there.
When you added IBase to the list of interfaces explicitly implemented by Implementation it worked, because that's the new starting point for lookup and it finds your new method.
You can either solve your problem by making the base member virtual and then overriding it in derived classes, or you can re-implement the interface by including that in the list for your Implementation class.
So the problem in my sample code is two-fold.
I assumed that in C# methods are "virtual" by default (as is in Java). Since I'm usually coding in Java, I've made an incorrect assumption.
See Is it possible to override a non-virtual method?
If I'd use virtual, I could override the method and achieve exactly the output I expected, as described in doc:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual namely "When a virtual method is invoked, the run-time type of the object is checked for an overriding member. The overriding member in the most derived class is called, which might be the original member, if no derived class has overridden the member."
My code, hovewer, is using method hiding, so unless I inform the compiler about my intention of using my implementation, it'll default to non-hidden method (as resolved by abstract class being the actual, original implementer)

Why can't a class with a type parameter used exclusively as an argument type be covariant on it?

The most common example I have found to explain why contravariantly-valid type parameters cannot be used covariantly has involved constructing some read-write wrapper of a derived type, casting it to a wrapper of the base type, injecting a different derived type, then later reading that wrapped value; something along the lines of the following:
class Base { public int base_property; }
class Derived : Base { public int derived_property; }
class OtherDerived : Base { public string other_derived_property; }
interface Wrapper<out T> {
void put(T v);
T pull();
}
Wrapper<Derived> derived_wrapper = new WrapperImpl<Derived>();
Wrapper<Base> cast_wrapper = (Wrapper<Base>)derived_wrapper;
cast_wrapper.put(new OtherDerived());
Derived wrapped = derived_wrapper.pull(); // Surprise! This is an OtherDerived.
I can understand why this is invalid. But what if Wrapper didn't have pull, and the property it wraps has a private getter? The problem with the (Wrapper<Base>)derived_wrapper cast seems to disappear, and I can't find a problem to replace it.
More specifically, I'm not aware of any way for functionality to be conditional on the eventual concrete type of a generic. Unsurprisingly, asserting the type like the following is no use:
class WrapperImpl<T> : Wrapper<T> where T : Base {
public void put(T v) {
if(typeof(T).Equals(Derived)) {
Console.WriteLine(v.derived_property); // Type `T' does not contain a
// definition for `derived_property'...
}
}
}
This leads me to believe that functionality in these methods can only make use of properties of the type T is constrained to. Even if the wrapped property is an OtherDerived where the original WrapperImpl expected a Derived (before being cast), no method could expect that wrapped property to have derived_property because Base is the most specific T is guaranteed to be.
Am I missing something here, or perhaps is this a limitation of the compiler to not be able to concretize T on the fly?
(I'm guessing that a class like Wrapper finds few uses, but the rules of variance appear quite broad and sweeping, and I'm curious if there are finer rules in play.)
The T in WrapperImpl<T> can be constrained on any subtype of Base, not just Base itself. Functionality in put should be able to safely access v.derived_property if T : Base is simply changed to a T : Derived.
This is the source of trouble when an OtherDerived is passed to put after the (Wrapper<Base>)derived_wrapper cast, in trying to access the nonexistent derived_property.

Is it a acceptable to hide a property in a derived interface which returns a derived type?

TL;DR
What is wrong with hiding a property in an interface so that I can change its declaration to return a derived type of the original property?
I'm sure this must have been asked before, but I can't find it, and apologies for the long question.
Say I have this situation:
public interface A
{
B TheB{get;}
}
public interface MoreSpecificA : A
{
MoreSpecificB TheMoreSpecificB{get;}
}
public interface B{...}
public interface MoreSpecificB:B{...}
I would like users of MoreSpecificA to be able to get at the B which is a MoreSpecificB. They could do this by calling TheB and cast it, or they could call the method TheMoreSpecificB. I could also declare MoreSpecificA like so:
public interface MoreSpecificA : A
{
new MoreSpecificB TheB{get;}
}
so that now they can just use the same method and get back a MoreSpecificB.
Using the new to hide a method puts my teeth on edge, so why is this a bad idea? It seems like a reasonable thing to do here.
The general suggestion in most cases I have seen for this seems to be to use generics instead, but this seems to have a problem in that if I have a MoreSpecificA and I want to return it in a method that declares the return type as A then I have to have MoreSpecificA extend A which gives ambiguity when accessing TheB on the MoreSpecificA instance as it doesn't know if you want A.TheB or MoreSpecificA.TheB
public interface ABase<T> where T : B
{
T TheB{get;}
}
public interface A : ABase<B>
{
}
public interface MoreSpecificA : ABase<MoreSpecificB>,A
{
}
public class blah
{
public A GetA(MoreSpecificA specificA)
{
return specificA; //can't do this unless MoreSpecificA extends A
}
public B GetB(MoreSpecificA specificA)
{
return specificA.TheB; //compiler complains about ambiguity here, if MoreSpcificA extends A
}
}
which could be solved by declaring a new TheB on MoreSpecificA (but the new issue again).
If MoreSpecificA doesn't extend A then the first method in the class blah above complains as now as MoreSpcificA can't be converted to A.
Whilst writing this I have noticed that if I declare my BaseA to be contravariant like this:
public interface ABase<out T> where T : B
{
T TheB{get;}
}
and my class to be
public class blah
{
public ABase<B> GetA(MoreSpecificA specificA)
{
return specificA;
}
public B GetB(MoreSpecificA specificA)
{
return specificA.TheB; //compiler complains about ambiguity here
}
}
Then I get the best of both worlds. Does the applicability of this solution depend on whether A adds anything to ABase?
Or is my original plan of just hiding the method in the derived type to return a derived type of the original method ok?
Or is my original plan of just hiding the method in the derived type to return a derived type of the original method ok?
So long as it means exactly the same thing, I think it's okay. You can see something like this in the standard libraries, with IDbConnection.CreateCommand (which returns IDbCommand) and SqlConnection.CreateCommand (which returns SqlCommand) for example.
In that case it's using explicit interface implementation for the IDbConnection version, but it's the same principle.
You can also see it in IEnumerator<T>.Current vs IEnumerator.Current and IEnumerable<T>.GetEnumerator() vs IEnumerable.GetEnumerator().
I would only use it in cases where the implementation for the more weakly-typed method just returns the result of calling the more strongly-typed method though, use implicit conversion. When they actually start doing different things, that becomes much harder to reason about later.

C# generic factory method

Perhaps this is a simple newbie C# question, but so be it---it will be a fresh break from my other questions, which are so difficult that no one knows the answer to them. :)
Let's say I have a generic type in C#:
Thing<T>
And let's say I want to make a thing using a static factory method. In Java, this is no problem:
public static <T> Thing<T> createThing()
{
return flag ? new Thing<Integer>(5) : new Thing<String>("hello");
}
How do I do this in C#? Thanks.
If you want to return an instance of a templated class using one of many different template arguments, one way to do it is with an abstract base (or an interface):
abstract class UntypedThing { }
class Thing<T> : UntypedThing
{
public Thing(T t) { }
}
class Foo
{
public static UntypedThing createThing(bool flag)
{
if (flag)
return new Thing<int>(5);
else return new Thing<String>("hello");
}
}
The UntypedThing class would contain as much code as possible that does not rely on the template type. The Thing class would ideally only contain code that relies on the template type. The factory class Foo always returns the former.
You can in theory use reflection to build up the correct generic type, but it will be pretty useless to you as at some point you will need to upcast it to a less specific type.
public class ThingFactory {
public object Create(bool flag) {
Type outputType = null;
if(flag) {
outputType = typeof(string);
} else {
outputType = typeof(int);
}
return Activator.CreateInstance(typeof(Thing<>).MakeGenericType(outputType));
}
}
As you can see, the value of doing this is about zero as you will need to cast the return type to the type you want, meaning that the logic to determine it needs to live outside the Create method.
I would use Reinderien's method and have a non-generic base. This is the most sane and idiomatic approach.
Oh, the trouble I get myself in when I simply try to do something simple.
It turns out that C# 4 allows this sort of covariance---sort of. First, I have to make Thing an interface and specify the "out" generic parameter:
public interface Thing<out T> {...}
But if I do certain things, C# won't let me use covariance. For example, if I try to return T from the interface:
public interface Thing<out T>
{
public T GetT();
Even if I manage to get covariance with Thing, what do I do with it?
Thing<object> thing=createThing();
The compiler tells me that the type cannot be inferred from usage.
Let's say I say screw the whole T thing and make the factory method return Thing of type object:
public static Thing<object> createThing() {...}
Fine, but now where do I put it?
IList<Thing<object>> list=new List<Thing<object>>();
Thing<object> thing=createThing();
list.Add(thing);
Yes, I have to say that this is a list of Thing with T of type Object, because C# has no wildcard type.
If this were Java, I'd simply say:
public class Thing<T> {...}
public static <T> Thing<T> createThing() {...}
List<?> things=new ArrayList<Thing<?>>();
Thing<?> thing=createThing();
things.add(thing);
If I wanted extra safety by saying that T had to be of a special type, I'd say:
public static <T extends MyBaseType> Thing<T> createThing() {...}
List<? extends MyBaseType> things=new ArrayList<Thing<? extends MyBaseType>>();
Thing<? extends MyBaseType> thing=createThing();
things.add(thing);
Then I'd figure out what T is later, when I had more information.
This all seems to come down to incomplete generic covariance in C# coupled with the lack of C# generic wildcards. (I still maintain it isn't an erasure issue.)
So what do I do? The only simple thing to do seems to follow Reinderien's answer and split out a non-generic base class.
(I wonder if in this non-generic base class I could have object getValue() and then use covariance in the subclass to return T getValue()? Ack, I'm tired of this---I'll leave that for another day.)

Why would you mask a base class member?

I have just learned how to mask a base class member (using new) but am missing the point as to why I would want to do that. Does masking provide us with a certain level of protection as is the case in using encapsulation? Please advise.
You will very rarely use "new" to mask a base class member.
It's mainly used for the cases where the derived class had the member first, and then it was added to the base class --- the same name for a different purpose. The new is there to that you acknowledge that you know you are using it differently. When a base member is added in C++, it just silently merges the existing method into the inheritance chain. In C#, you will have to choose between new and override, to show you know what is happening.
It's not just used for masking. It actually breaks the inheritance chain, so if you call the base class method, the method in the derived class will not be called (just the one in the base class).
You're essentially creating a new method that has nothing to do with the base class method. Hence the "new" keyword.
Keeping that in mind the "new" keyword can be used if you want to define a method with the same signature as a base type method, but having a different return type.
The only valid safe examples that I've come across is being more specific with return types or providing a set accessor on a property. I'm not saying those are the only ones, but that's all I've found.
For example, suppose you have a very simple base that looks like this:
public abstract class Base
{
public string Name { get; protected set; }
public Base(string name)
{ Name = name; }
}
You could have a derived that looks more like this:
public class Derived : Base
{
public new string Name
{
get { return base.Name; }
set { base.Name = value; }
}
public Derived(string name) : base(name)
{ }
}
Assuming business rules allows this one specific Derived to have a changeable name, I believe this is acceptable. The problem with new is that it changes behavior depending on what type the instance is viewed as. For example, if I were to say:
Derived d = new Derived("Foo");
d.Name = "Bar";
Base b = d;
b.Name = "Baz"; // <-- No set available.
In this trivial example, we're fine. We are overriding the behavior with new, but not in a breaking way. Changing return types requires a bit more finesse. Namely, if you use new to change a return type on a derived type, you shouldn't allow that type to be set by the base. Check out this example:
public class Base
{
public Base(Base child)
{ Child = child; }
public Base Child { get; private set; }
}
public class Derived
{
public Derived(Derived child) : base(child)
{ }
public new Derived Child
{ get { return (Derived)base.Child; } }
}
If I could set Child on the Base class, I could have a casting problem in the Derived class. Another example:
Derived d = new Derived(someDerivedInstance);
Base b = d;
var c = b.Child; // c is of type Base
var e = d.Child; // e is of type Derived
I can't break any business rules by treating all of my Derived classes as Bases, it's just convenient to not type check and cast.
I have just learned how to mask a base class member (using new)
FYI this feature is usually called "hiding" rather than "masking". I think of "masking" as clearing bits in a bit array.
am missing the point as to why I would want to do that.
Normally you don't want to. For some reasons to use and not use this feature, see my article on the subject from 2008:
http://blogs.msdn.com/b/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx
Does masking provide us with a certain level of protection as is the case in using encapsulation?
No, it does not.
What you are referring to is called Name Hiding. It is mostly a convenience feature. If you are inheriting from a class for which you do not control the source using new will let you change the behavior of a method even if it wasn't declared as virtual (or completely change the signature if it is virtual). The new keyword simply suppresses a compiler warning. You are basically informing the compiler that you are intentionally hiding the method from a parent class.
Delphi had the reintroduce keyword for the same reason.
What does this buy you other than a suppressed warning? Not a whole lot. You can't access the new method from a parent class. You can access it from an interface if your child class directly implements the interface (as apposed to inheriting it from its parent class). You can still call the parent class' member from the child. Any additional descendants of your class will inherit the new member rather than the one in the parent.
This is actually called member hiding. There are a couple of common scenarios where this can be appropriately used.
It allows you to work around versioning issues in which either the base or derived class author unwittingly creates a member name that collides with an existing identifier.
It can be used to simulate covariance on return types.
Regarding the first point...it is possible that an author of a base class could later add a member with the same name as an exisiting member in a derived class. The base class author may not have an knowledge of the derived classes and thus there is no expectation that she should avoid name collisions. C# supports the independent evolution of class hierarchies using the hiding mechanisms.
Regarding the second point...you may want a class to implement an interface that dictates a certain method signature and so you are locked into returning instances of a certain type only while at the same time you have subclassed that type and would really like for callers to see the concrete type instead. Consider this example.
public interface IFoo { }
public class ConcreteFoo { }
public abstract class Base
{
private IFoo m_Foo;
public Base(IFoo x) { m_Foo = x; }
public IFoo Foo { get { return m_Foo; } }
}
public class Derived
{
public Derived(ConcreteFoo x) : base(x) { }
public new ConcreteFoo Foo { get { return (ConcreteFoo)base.Foo; } }
}

Categories

Resources