Abstract class and interface with the same generic method - c#

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>();

Related

Non-generic class implementation of generic interface is not inherited

If I have this code:
public interface IThing<T> where T : class
{
// ...
}
public class BaseThing<T> : IThing<T> where T : class
{
// ...
}
public class ThingA : BaseThing<string>
{
// ...
}
public class ThingB : BaseThing<Uri>
{
// ...
}
This code fails:
List<IThing<object>> thingList = new List<IThing<object>>();
thingList.Add(new ThingA());
thingList.Add(new ThingB());
Even though ThingA (indirectly) inherits from (and should be an instance of) IThing<T>. Why? Is ThingA/ThingB not an instance of IThing<T>?
This would require your interface to be covariant. For details, see Covariance and Contravariance in Generics.
In this case, you can make this work by using:
// Add out here
public interface IThing<out T> where T : class
{
}
Note that this does place limitations on the interface and what you can do with it, however, as it requires that the type T in the interface be used only as a method return type within the interface, and not used as a type of formal method parameters.
If this is not viable, another option is to create a non-generic IThing interface, and have IThing<T> implement IThing. You could then use List<IThing> for your collection.

What is this C# construct doing and why? MyClass<TMyClass> : MyClass where

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.

Explicit generic method implementation with 2 Type parameters -- only explicitly name 1 Type Parameter

I have an interface that has a generic method with two type parameters. I want to partially explicitly implement that generic method in a class. Is this possible? Some example code below:
public interface ISomeInterface
{
TResultType Results<TResultsType,TSearchCriteriaType>(TSearchCriteriaType searchCriteria);
}
public class SomeConcrete : ISomeInterface
{
public TResultsType Results<TResultsType, ConcreteSearchCriteria>(ConcreteSearchCriteria searchCriteria)
{
return (TResultsType)Results;
}
}
Do I have to explicitly implement both type parameters to make this work?
Do I have to explicitly implement both type parameters to make this work?
In order to implement this interface, your class must allow ANY types to be used for that method. (Any types which fit the constraints defined in the interface, which, in this case, since there are no constraints, means any type.)
You can't restrict the interface within a specific class implementing it, since this is a generic method (not a generic type), and there is no constraints which cause this to work properly.
In order to do what you wish, I think, you'd need to make the interface generic:
public interface ISomeInterface<TSearchCriteriaType>
{
TResultType Results<TResultsType>(TSearchCriteriaType searchCriteria);
}
You can then implement it as:
public class SomeConcrete : ISomeInterface<ConcreteSearchCriteria>
{
public TResultsType Results<TResultsType>(ConcreteSearchCriteria searchCriteria)
{
var results = GenerateResults();
return (TResultsType)results;
}
}
By making the interface generic on the search criteria, you allow your class to implement it based on a specific type for the search criteria.
I think this is what you're looking for:
public class SomeConcrete : ISomeInterface
{
TResultsType ISomeInterface.Results<TResultsType, TSearchCriteriaType>(TSearchCriteriaType searchCriteria)
{
return Results<TResultsType>((ConcreteSearchCriteria)(object)searchCriteria);
}
public TResultsType Results<TResultsType>(ConcreteSearchCriteria searchCriteria)
{
// return something
}
}
Note that this will fail at run time, though the compiler can see no problems:
ISomeInterface someInterface = new SomeConcrete();
var result = someInterface.Results<object, SomeOtherSearchCriteria>(null);
More generally, you're no longer implementing the interface as might be expected. You might want to make it ISomeInterface<TResultsType, TSearchCriteriaType>, then make SomeConcrete<TResultsType> : ISomeInterface<TResultsType, ConcreteSearchCriteria>. That way you are implementing the interface as expected, declaring it all strongly.
You can't specialize a generic method like that. If it's generic in the interface, it has to be generic in the implementing classes. If you move the type parameters to the interface itself, then you can do it (and you can also have variance annotations, making it covariant in the result type and contravariant in the search criteria type):
public interface ISomeInterface<out TResultsType, in TSearchCriteriaType> {
TResultsType Results(TSearchCriteriaType searchCriteria);
}
public class SomeConcrete<TResultsType> :
ISomeInterface<TResultsType, ConcreteSearchCriteria> {
public TResultsType Results(ConcreteSearchCriteria searchCriteria) {
...
}
}
Now your class is generic on the result type.
You can also have a class specialized in a certain result type, and generic in the criteria type:
public class IntSearcher<TSearchCriteriaType> :
ISomeInterface<int, TSearchCriteriaType> {
public int Results(TSearchCriteriaType searchCriteria) {
...
}
}
I think this is a more consistent design, since both generic parameters are at the same level (and it looks like they should go together). But only you can say whether this is better for your code or not.
Yes, I think you do, otherwise you are not directly implementing the interface.
Your Implementation is not as generic as the interface contract.

C# Method Overload Problem With Class Derived From Generic Abstract Class

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.

Implementing an abstract method which is itself an implementation of a generic interface method

I get compile errors with this overcomplicated class hierarchy. I wonder if it has anything to do with trying to do DeepCopy() with generics mixed in.
public interface IInterface<T>
{
IInterface<T> DeepCopy();
}
public abstract class AbstractClass<T> : IInterface<T>
{
public abstract IInterface<T> DeepCopy(); // Compiler requires me to declare this public
}
// Everything good at this point. There be monsters below
public class ConcreteClass: AbstractClass<SomeOtherClass>
{
ConcreteClass IInterface<SomeOtherClass>.DeepCopy()
{
return new ConcreteClass;
}
}
I get the following compiler errors:
'IInterface<...>.DeepCopy()': containing type does not implement interface 'IInterface<SomeOtherClass>'
Return bool
Change ConcreteClass IInterface<SomeOtherClass>.MyMethod()
to bool IInterface<SomeOtherClass>.MyMethod()
Edit:
And then you can not use an explicit implementation of the interface, since that does not fulfill the contract of the abstract class you need to implement it like this.
public override IInterface<SomeOtherClass> DeepCopy()
{
return new ConcreteClass();
}
The errors are because the return type of DeepCopy() do not match the declaration in the interface.
Besides that you have a different problem. The abstract class already implements the method from the interface, but in the concrete class you do not implement the abstract method. Instead of the implementation you now have, you should have the following implementation:
public override IInterface<SomeOtherClass> DeepCopy()
{
}
This will implement the abstract method in the abstract class which automatically implements the method in the interface. The reason you need to implement the abstract method in the abstract class, is because that class needs to implement the interface. That is a requirement of a class.

Categories