How to Inherit method but with different return type?
Given the following classes:
ClassA
{
public ClassA DoSomethingAndReturnNewObject()
{}
}
ClassB : ClassA
{}
ClassC : ClassA
{}
Is there a way to get ClassB
and ClassC
to inherit the method but customize the return type to their own class?
I prefer not to copy the method from ClassA and change the typ开发者_运维百科e there.
I need to get a ClassB
object when I call ClassB.DoSomethingAndReturnNewObject()
.
I need to get a ClassC
object when I call ClassC.DoSomethingAndReturnNewObject()
.
Something like calling a constructor based on current type like: this.GetType()
? But I have no clue how to actually do that.
No, the feature you mentioned is called return type covariance. It's not supported in C#.
You need to create a protected virtual method for the DoSomethingAndReturnNewObject
to use:
class ClassA
{
protected virtual ClassA Create()
{
return new ClassA()
}
public ClassA DoSomethingAndReturnNewObject()
{
ClassA result = Create();
// Do stuff to result
return result;
}
}
class ClassB : ClassA
{
protected override ClassA Create() { return new ClassB(); }
}
class ClassC : ClassA
{
protected override ClassA Create() { return new ClassC(); }
}
Note the return type remains ClassA but the object instance type will be the specific class.
What you're describing is a covariant return type and is not supported in C#.
However, you could create ClassA as an open generic and have the closed generic inheritors return their own type.
Example:
public abstract class ClassA<T> where T: ClassA<T>, new()
{
public abstract T DoSomethingAndReturnNewObject();
}
public class ClassB: ClassA<ClassB>
{
public override ClassB DoSomethingAndReturnNewObject()
{
//do whatever
}
}
class ClassA<T> where T : ClassA<T>, new()
{
public T DoSomethingAndReturnNewObject()
{
return new T();
}
}
class ClassB : ClassA<ClassB> { }
class ClassC : ClassA<ClassC> { }
Test:
ClassB b1 = new ClassB();
ClassB b2 = b1.DoSomethingAndReturnNewObject(); // returns instance of ClassB
Well, the correct answer is no and, generally, this is a bad idea. If you are returning something completely different, find another way.
However, if you aren't returning something completely different, an interface can solve your issue. Instead of returning a class, return an interface and have classes A, B, and C return objects that implement that interface in the way they see fit.
This isn't inheritance, because the return type of the method is part of its signature. You're not changing the method, you'd be creating an entirely new one.
You do have some options. You could, for example, make the method DoSomethingAndReturnNewObject
a generic-based method, and have it return its generic type. This is probably the most direct path to the exact behavior for which you're looking.
The other alternative is to leave the method signatures as-is, and have the subclass methods return instances of ClassB
and ClassC
. Then the client code would need to be responsible for casting in order to use those objects as their appropriate derived classes.
Is there some reason the common interface of ClassA
doesn't suffice? Polymorphism will, if you have derived and overridden virtual members correctly, provide you with the correct functionality if you're only using the ClassA
members.
Maybe generics will be your saviour. Take a look at this link: C# Generics Part 3/4: Casting, Inheritance, and Generic Methods
bstract class B<T> {
public abstract T Fct(T t);
}
class D1 : B<string>{
public override string Fct( string t ) { return "hello"; }
}
class D2<T> : B<T>{
public override T Fct(T t) { return default (T); }
}
I finally devised the following solution. For my case it's useful enough, but it assumes that ClassA knows about it's derivatives and is limited to those two options. Not really high-level thinking, but it works. :)
ClassA
{
public ClassA DoSomethingAndReturnNewObject()
{
if (this.GetType() == typeOf(ClassB))
{
return new ClassB(values);
}
else
{
return new ClassC(values):
}
}
}
ClassB : ClassA
{}
ClassC : ClassA
{}
I think that you need to create a new function with the new return type and call inside the other function, and manipulate the type returned. otherwise it will no be logical ! (with the definition/idea of inheritance)
There's one really simply answer: make all the method return types "object". You're obviously returning different types, strings and ints and whatnots, and they will stay what they are after they reach their destination. But the compiler is perfectly happy - everything's an "object". You do give up compile-time type-checking, not a good thing, but every once in a while for some deep OO programming the return is worth it.
精彩评论