I am working on a project, and I have a generic abstract type that takes a type parameter that is itself derived from the abstract type. If you want to know why I would do this, please see this question.
I have run into an interesting problem with overloading a method in a derived class that is defined in the abstract class. Here is a code sample:
public abstract class AbstractConverter<T, U>
where U : AbstractConvertible
where T : AbstractConverter<T, U>
{
public abstract T Convert(U convertible);
}
public class DerivedConvertibleConverter : AbstractConverter<DerivedConvertibleConverter, DerivedConvertible>
{
public DerivedConvertibleConverter(DerivedConvertible convertible)
{
Convert(convertible);
}
public override DerivedConvertibleConverter Convert(DerivedConvertible convertible)
{
//This will not be called
System.Console.WriteLine("Called the most derived method");
return this;
}
public DerivedConvertibleConverter Convert(Convertible convertible)
{
System.Console.WriteLine("Called the least derived method");
return this;
}
}
public abstract class AbstractConvertible {}
public class Convertible : AbstractConvertible {}
public class DerivedConvertible : Convertible {}
In the sample above, the overload of Convert that does not exist in the abstract parent (and is less derived) is called. I would expect that the most derived version, from the parent class, would be called.
In trying to troubleshoot this problem, I ran into an interesting solution:
public abstract class AbstractConverter<U>
where U : AbstractConvertible
{
public abstract AbstractConverter<U> Convert(U convertible);
}
public class DerivedConvertibleConverter : AbstractConverter<DerivedConvertible>
{
public DerivedConvertibleConverter(DerivedConvertible convertible)
{
Convert(convertible);
}
public override DerivedConvertibleConverter Convert(DerivedConvertible convertible)
{
System.Console.WriteLine("Called the most derived method");
return this;
}
public DerivedConvertibleConverter Convert(Convertible convertible)
{
System.Console.WriteLine("Called the least derived method");
return this;
}
}
public abstract class AbstractConvertible {}
public class Convertible : AbstractConvertible {}
public class DerivedConvertible : Convertible {}
When the derived type argument is removed from the base class, the most derived version of Convert is called. I would not expect this difference, since I would not have expected the interface of the abstract version of Convert to have changed. However, I must be wrong. Can anyone explain why this difference occurs? Thank you very much in advance.
In the sample above, the overload of Convert that does not exist in the abstract parent (and is less derived) is called. I would expect that the most derived version, from the parent class, would be called
Many people have this expectation. However, the behaviour you are observing is correct and by design.
The overload resolution algorithm goes like this. First we make a list of all the possible accessible methods you could be calling. Methods which override virtual methods are considered to be methods of the class which declared them, not the class which overrode them. Then we filter out the ones where the arguments cannot be converted to the formal parameter types. Then we filter out all the methods that are on any type less derived than any type that had an applicable method. Then we determine which method is better than another, if there is still more than one method left.
In your case there are two possible applicable methods. The one that takes a DerivedConvertible is considered to be a method of the base class, and is therefore not as good as the one that takes a Convertible.
The principle here is that overriding a virtual method is an implementation detail subject to change, and not a hint to the compiler that the overriding method is to be chosen.
More generally, these features of the overload resolution algorithm are designed to help mitigate various versions of the Brittle Base Class problem.
For more details about these design decisions see my article on the subject:
http://blogs.msdn.com/b/ericlippert/archive/2007/09/04/future-breaking-changes-part-three.aspx
When the derived type argument is removed from the base class, the most derived version of Convert is called. I would not expect this difference, since I would not have expected the interface of the abstract version of Convert to have changed
The question is based on a false premise; the most derived version is not called. The program fragment is erroneous, and therefore does not compile, and therefore neither method is called; the program doesn't run because it does not compile.
Related
I have the following code:
internal abstract class Base
{
internal abstract object Method1();
}
internal abstract class Base<T> : Base
{
new internal abstract T Method1();
}
I have no idea why this is able to compile. Here are my questions:
Why am I able in a derived class to define another abstract method which differs only by the returned type.
Why does the new modifier even work on abstract methods? At lest from my point of view it doesn't make any sense because Base has no implementation for it
Of course I'm not able to create any non abstract class that actually inherits from Base<T> but why was I able to do this in the first place?
After the first set of comments look like there's some room for improvement:
Why am I able in a derived class to define another abstract method
which differs only by the returned type.
This can be done even without the new keyword take for example:
class Program
{
static void Main(string[] args)
{
var obj = (Derived) new Object();
int result = obj.Method1();
}
}
internal abstract class Base1
{
internal abstract string Method1();
}
internal abstract class Derived: Base1
{
internal abstract int Method1();
}
The problems here are:
It is impossible to create a class which inherits from Derived
VS Intelisense tells you that there's an overload for that methods but it's just not able to display it.
While the answer might be that this doesn't make sense in the first place, I find this behavior a bit inconsistent because there are other places in the language when things which don't make sense cause a compile time error. An example is when trying to have a generic type constraint for a sealed or concrete value type.
As for my second question, it looks more like it's just a side effect of the first.
I have a base class, say named B. I have two derived classes, D1 and D2.
Looks like:
public abstract class B
{
public abstract void DoSomething();
}
public class D1 : B
{
public override void DoSomething() { ... }
}
public class D2 : B
{
public override void DoSomething() { ... }
}
Now, I created a new interface IDeepCopyable<T> which has one method Clone():
public interface IDeepCopyable<T>
{
T Clone();
}
I want to force each subclass too implement this interface with the base class (i.e. IDeepCopyable<B>.
If I try to leave B's declaration as-is but just inherit from ('implement' is a more accurate term?) IDeepCopyable<T>, such as:
public abstract class B : IDeepCopyable<B>
Then to implement it in the derived classes (either implicitly or explicitly), the compiler gives me an error message "B does not implement interface member IDeepCopyable<B>.Clone()".
I can, of course, create an abstract method whose name is identical to the interface's method's name, but I find that ugly. Why to redeclare the method?
Can I, in any way, leave that as wanted?
I see that VS2019 has an option "Implement interface abstractly" so I think that the answer is no, but A) I want to be sure. B) If so, is there a design concept behind this behavior, or is it just a bug in C# design?
Thanks in advance.
I can, of course, create an abstract method whose name is identical to the interface's method's name, but I find that ugly.
That's the way to go. Your base class implements the interface. Hence it has to fulfil it. It can do this by implementing the method concretely (which is not desired here) or the base class can force its inheritors to do so by declaring the method abstractly.
You say that's ugly, well I think it's just explicit.
Anyway, there's no way around this ;-)
I came across the following code, all in a single file/class. I'm leaving out the details, its the construct I'm interested in. Why are there two different declarations for the same class and how are they different? What's the purpose of the syntax for the second declaration?
public abstract class MyClass
{
...
}
public abstract class MyClass<TMyClass> : MyClass
where TMyClass: MyClass<TMyClass>
{
...
}
MyClass - A abstract class named MyClass.
MyClass<TMyClass> : MyClass - A abstract generic class named MyClass<> but with a generic type named TMyClass.
If you rename the types, it will be easier to see:
public abstract class MyBaseClass
{
...
}
public abstract class MyClass<T> : MyBaseClass
where T: MyClass<T>
{
...
}
Types with different generic arity (i.e. number of generic type parameters, which can be zero or more) are considered as completely unrelated by the language and can have the same name.
This means that you can have classes Foo, Foo<T> and Foo<T,U> at the same time; the syntax will allow the compiler to determine which you are referring to. You can see this happen in the base framework which includes Action, Action<T> etc.
The "recursive" construct class C<T> where T: C<T> (the inheritance from a non-generic C does not change anything so I removed it) is the C# on what is called the Curiously Recurring Template Pattern (CRTP) in C++. Eric Lippert has covered this subject very well in a blog post, where the conclusion is that one should think more than twice before implementing this -- there are problems it can solve, but the solution also has a price.
public abstract class MyClass<TMyClass> : MyClass
where TMyClass: MyClass<TMyClass>
{
...
}
is a class that inherits from MyClass, and it takes a generic type, which has to inherit from MyClass<TMyClass>
Here's a simpler example of the same thing for you
public static void Main()
{
MyClass<Myclass> other = new MyClass<Myclass>(new Myclass());
List<int> intlist = new List<int>();
}
public class Myclass
{
public Myclass()
{
}
public int i { get; set; }
}
public class MyClass<T> where T : Myclass
{
T value;
public MyClass(T val)
{
value = val;
}
}
}
It's a classic idiom, the Curiously Recurring Template Pattern, done in C#.
It means the template can only be used thusly:
class Foo : MyClass<Foo>
{
}
In this construction, Foo inherits MyClass<Foo> which inherits MyClass.
This has a few advantages, but I've forgotten which.
public abstract class MyClass<TMyClass> : MyClass
where TMyClass: MyClass<TMyClass>
{
...
}
First thing to point out is that this is an abstract class that is inheriting from another abstract class. In other words, this is a class that cannot be instantiated (without another class inheriting from it), but is using inheritence to derive the functionality from another abstract class (which is fine).
The second thing to point out, is that this is a Template class (or generic class as they call it in C#) which accepts type in it's . I would reduce that to T as a convention so that T is always a template, though it is completely up to you what you call things.
Lastly there is a constraint on this which is kind of strange. It says that, no matter what, the compiler will not allow any class type to be passed in as a template type, unless it inherits from (somewhere along the inheritance chain)
MyClass<TMyClass>
This is shown in the following line
where TMyClass: MyClass<TMyClass>
basically this prevents anyone from passing in an object that does not follow this rule.
What is a bit odd is that the constraints tells the implementer that it cannot be a template unless the type passed by template is in fact a type of itself. You as the designer of this class (or implementer) has to decide if this is a wise design, though this in itself looks a bit strange.
I'm trying to create a set of classes with different level of abstraction. I will use the Vector example here.
My goal is that the user of my classes can choose the level of abstraction to use i.e. they may or may not want to be using the more derived class.
interface IVector
{
Vector A();
}
interface ISparseVector : IVector
{
new SparseVector A();
}
Now, I implement the classes as such:
class Vector : IVector
{
public Vector A() { return new Vector(); }
}
class SparseVector : Vector,ISparseVector
{
public new SparseVector A() { return new SparseVector(); }
}
This is all fine and dandy. However, when the base class is abstract such as:
abstract class Vector : IVector
{
public abstract Vector A();
}
class SparseVector : Vector,ISparseVector
{
public SparseVector A() { return new SparseVector(); } // Hides abstract member.
}
I get a compile error saying that the derived method is hiding the abstract method in Vector. Any idea of how to get around this?
The feature you want is called "return type covariance", and it is not a feature of C#. Return type covariance is the feature where you can have a virtual method that return an Animal, and then you override that with a method that returns a Giraffe.
Doing so is typesafe and some languages do have this feature -- C++ for example -- but C# does not and we have no plans to add it. Your overriding method has to be marked override, and it has to match exactly -- in name, formal parameter types, and return type.
The reason is in your first example on the Vector class, you weren't specifying an access level for the A() method. This means it is a private method, which is the default. You could use the new keyword in the SparseVector class to get around this error.
For a start, you should look at this thread which specifies why you cannot have an abstract constructor.
Why can't I create an abstract constructor on an abstract C# class?
Then, you should put an abstract method in your Vector class that can actually be overridden to provide implementation, as abstract methods are supposed to be.
You can't mix abstract and interface methods the way you're trying. If you were to declare 'Vector' abstract and override the implementation of A(), you'd be overriding 'Vector A()' from your abstract class, but that wouldn't implement the interface ISparseVector.Vector, which has a return type of ISparseVector.
Your use-case doesn't appear to require that 'Vector' be abstract.
I'm writing two APIs that I will use with many of my projects. Some projects my use one of the APIs, some the other, but the majority of my projects will use both. I'm trying to design them as if they're completely separate, but I'm struggling on one thing.
namespace FirstApi {
public abstract class MyBaseClass {
//constructor, some methods and properties
public IEnumerable<T> Search<T>() where T : MyBaseClass, new() {
//search logic here. must use generics as I create new instances of T here
}
}
}
namespace SecondApi {
public interface IMyInterface {
//some property and method signatures
IEnumerable<T> Search<T>() where T : IMyInterface, new();
}
}
namespace MyProject {
public class MyDerivedClass : MyBaseClass, IMyInterface {
}
}
Both APIs require this search method. The second API has some functionality in other classes that calls IMyInterface.Search<T>(), and I would like those classes that inherit MyBaseClass to use the Search<T> function defined in MyBaseClass.
Compilation error: The constraints for type parameter 'T' of method 'MyBaseClass.Search()' must match the constraints for type parameter 'T' of interface method 'IMyInterface.Search()'. Consider using an explicit interface implementation instead.
Note: When Search is called, T will always be the derived class of whichever abstract class or interface has been inherited. This was the only way I could find of achieving this in C# 2.0 (C# abstract class return derived type enumerator), and it's just caused more problems!
Is there a type-safe way that I can achieve this, without using objects and casting?
Solution:
Based on the accepted answer by Andras Zoltan, I created this class in my project, and will have to re-create this class for each project that uses both APIs.
public abstract class ApiAdapter<TAdapter> : MyBaseClass, IMyInterface where TAdapter: MyBaseClass, IJsonObject, new()
{
IEnumerable<T> IJsonObject.Search<T>()
{
foreach (TAdapter row in base.Search<TAdapter>())
yield return (T)(IMyInterface)row;
}
}
I then inherit this class like so.
public class Client : ApiAdapter<Client> {
//everything else can go here
}
You can explicitly implement the interfaces Search method, e.g.
public class MyDerivedClass : BasicTestApp.FirstApi.MyBaseClass, BasicTestApp.SecondApi.IMyInterface
{
IEnumerable<T> SecondApi.IMyInterface.Search<T>()
{
// do implementation
}
}
However, I think you are asking for the MyBaseClass Search method to be called when the part of the code that handles your object as IMyInterface calls the Search<T> method. I cannot see a way because you have two T types with different constraints that cannot be related.
If you did where T : BasicTestApp.FirstApi.MyBaseClass, IMyInterface, new(); in both definitions of the Search method then you would not have a problem but this would tie both your APIs together
Here is a possible implementation of your explicitly implemented interface method. It doesn't avoid the cast but at least keeps it neat.
IEnumerable<T> SecondApi.IMyInterface.Search<T>()
{
var results = base.Search<MyDerivedClass>();
return results.Cast<T>();
}
I started my answer with exposition on why it's not working for you, but I think that's well understood now so I'll leave it out.
I've upvoted #IndigoDelta's answer but it highlights something I don't like about the overall design here - I have a sneaking suspicion you should actually be using a generic interface and generic class; not generic methods because it doesn't make any sense that:
Note: When Search is called, T will always be the derived class of whichever abstract class or interface has been inherited.
I'm throwing this solution into the mix; which I think is better because it means that each derived type doesn't need to reimplement the IMyInterface.Search method, and it goes some way to actually enforcing this rule you mention. It's a generic type dedicated to join the two APIs together, meaning the derived types don't need to do anything:
namespace MyProject
{
using FirstApi;
using SecondApi;
public class SecondAPIAdapter<T2> : MyBaseClass, IMyInterface
where T2 : SecondAPIAdapter<T2>, new()
{
#region IMyInterface Members
IEnumerable<T> IMyInterface.Search<T>()
{
return Search<T2>().Cast<T>();
}
#endregion
}
//now you simply derive from the APIAdapter class - passing
//in your derived type as the generic parameter.
public class MyDerivedClass : SecondAPIAdapter<MyDerivedClass>
{ }
}
i think you can do explicit implementation of interface and when you will access methor thru IMyInterface.Search - compiler will run the right method.
You need to use an explicit implementation.
public class MyDerivedClass : MyBaseClass, IMyInterface
{
// The base class implementation of Search inherited
IEnumerable<T> IMyInterface.Search<T>()
{
// The interface implementation
throw new NotImplementedException();
// this would not work because base does not implement IMyInterface
return base.Search<T>();
}
}
Since the implementations are different this makes sense. If they are not different then either the base class should implement the interface and you should use covariance (.Net 4.0 only) to combine your contraints or, perhaps you don't need the interface at all.
I hope I'm not confused, could you not change your definitions, such that:
public interface IMyInterface<in T>
{
//some property and method signatures
IEnumerable<U> Search<U>() where U : T, new();
}
Providing a generic argument of T which can use to enforce that the implementation provides a search function constraint to types of T:
public abstract class MyBaseClass : IMyInterface<MyBaseClass>
{
public virtual IEnumerable<T> Search<T>() where T : MyBaseClass, new()
{
}
}
That way, your derived types are simply:
public class MyDerivedClass : MyBaseClass
{
}
Which you can then do searches as:
var derived = new MyDerivedClass();
IMyInterface<MyDerivedClass> iface = impl;
var results = iface.Search<MyDerivedClass>();