Non-generic class implementation of generic interface is not inherited - c#

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.

Related

Can I use unrelated types as constraints in generic classes? [duplicate]

This question already has answers here:
C# Multiple generic constraints
(7 answers)
Closed 9 years ago.
I want to create a generic class where T parameter can be any instance from the set of other types.
So this code compiles fine:
public interface TestA { }
public interface TestB { }
public class Test<T> where T : TestA, TestB
{
}
However, when I try to use it like this
var a = new Test<TestA>();
var b = new Test<TestB>();
I get two compile errors:
Error 1 The type 'TestA' cannot be used as type parameter 'T' in the
generic type or method 'Test'. There is no implicit reference
conversion from 'TestA' to 'TestB'.
Error 2 The type 'TestB' cannot be used as type parameter 'T' in the
generic type or method 'Test'. There is no implicit reference
conversion from 'TestB' to 'TestA'.
I am confused as to why this doesn't work. How can I workaround this? Ideally, I'd like TestA and TestB classes to have no relation (eg. no inheritance between them).
The type must follow all contraints defined on the generic type (AND, not OR).
If you want to allow both TestA or TestB, you should define a base interface :
public interface TestBase { }
public interface TestA : TestBase { }
public interface TestB : TestBase { }
public class Test<T> where T : TestBase
{
}
Well you specified that the class must implement both interfaces. So you must give it a class that implements both interfaces, not just A or B
public class LikeThis : TestA, TestB
{
// have both A and B's properties, methods, etc.
}
var a = new Test<LikeThis>();
The other option is to make both TestA and TestB inherit from a base interface
public interface IBaseInterface { }
public interface IInterfaceA { }
public interface IInterfaceB { }
public class Test<T> where T : IBaseInterface
{
}
var a = new Test<IBaseInterface>();
But it is hard to tell what you are trying to accomplish here. The Test class could possibly hold a reference to IBaseInterface as a property, but it will not know if it is InterfaceA or InterfaceB.
Maybe if you tell us what you are trying to accomplish we can suggest a better solution.
The constraints on the type parameter are conjunctive (AND), so any type used there must implement both interfaces.
One way, as already mentioned, is to create a super-interface to both interfaces and constrain your type parameter to that (note that I added the usual interface prefix I):
public interface IBase { }
public interface ITestA : TestBase { }
public interface ITestB : TestBase { }
public class Test<T> where T : IBase {
}
That has the disadvantage that it's not just implementers of ITestA or ITestB that can be used as type parameters in Test<T>, but any other type that implements IBase.
Another option is to provide a super class that cannot be inherited from outside your assembly and create two sub-classes from it, one for each desired interface type:
public interface ITestA { }
public interface ITestB { }
public abstract class Test<T> {
internal Test() { }
}
public class Test1<T> : Test<T> where T : ITestA { }
public class Test2<T> : Test<T> where T : ITestB { }
Now the Test<T> superclass cannot be inherited from outside your assembly (it has an internal constructor). Your classes (Test1<T> and Test2<T>) just use the logic of the superclass and each works with one of the desired interfaces as a constraint. Client code would have to choose which one to use based on the interface constraint they'd like to use.
Also, if you have common code in your interfaces that you'd like to use inside Test<T>, you should extract that to a super-interface and have your super-class be constrained by it, resulting in a hybrid of both approaches:
public interface IBase { }
public interface ITestA : IBase { }
public interface ITestB : IBase { }
public abstract class Test<T> where T : IBase {
internal Test() { }
}
public class Test1<T> : Test<T> where T : ITestA { }
public class Test2<T> : Test<T> where T : ITestB { }

Is there a way to express a generic handler in a generic way in C#?

Imagine I have an interface that specifies some collection handler:
interface ICollectionHandler<T> where T : new() { ... }
I then have same other class that wants a collection handler, which it will use for various types, so I want to do something like:
class SomeClass<T> where T : ICollectionHandler<> ...
If I do this though, I get an error saying that the "Type argument is missing".
So is there a way of specifying that T is a generic type, whose own type argument can be specified at runtime, or am I pushing C# beyond its (possibly sensible) boundaries here?
You could try something like:
interface ICollectionHandler<T> where T : new() { }
public class MyImplementation<T, U> where T : ICollectionHandler<U> { }
I'm pretty sure that knowing which generic type reside inside your implementation of your interface is required. If you don't care about that sub-type:
interface ICollectionHandler { }
public abstract class CollectionHandler<T> : ICollectionHandler where T : new() { }
public class MyImplementation<T> where T : ICollectionHandler { }
But it really depends how you are gonna use that and in what context. Maybe you can give more details?
You can create a base interface for ICollectionHandler<T> and constrain against it.
interface ICollectionHandler { ... }
interface ICollectionHandler<T> : ICollectionHandler where T : new() { ... }
class SomeClass<T> where T : ICollectionHandler { ... }
Or add a parameter to SomeClass representing the Type that should be passed into the ICollectionHandler<T> constraint:
class SomeClass<T, U> where T : ICollectionHandler<U> { ... }
You can add a second type parameter to SomeClass:
class SomeClass<T, U> where T : ICollectionHandler<U> ...

c# 3.0 Casting an interfaced generic type

Given these base classes and interfaces
public abstract class Statistic : Entity, IStatistic
{
protected abstract IStatisticsRepository<IStatistic> Repository {get;}
...
public class AverageCheckTime : Statistic
...
public interface IStatisticsRepository<T> : IRepository<T> where T : IStatistic
...
public interface IAverageCheckTimeRepository : IStatisticsRepository<AverageCheckTime>
...
public class AverageCheckTimeRepository : StatisticRepository<AverageCheckTime>, IAverageCheckTimeRepository
...
public class RepositoryFactory
{
public static IAverageQueueTimeRepository AverageQueueTimeRepository
{
get { return CurrentServiceLocator.GetInstance<IAverageQueueTimeRepository>(); }
}
Why does AverageCheckTime's implementation throw an invalid cast exception:
protected override IStatisticsRepository<IStatistic> Repository
{
get { return (IStatisticsRepository<IStatistic>)RepositoryFactory.AverageCheckTimeRepository; }
}
How do I cast an instance of IAverageCheckTimeRepository as an IStatisticsRepository<IStatistic> which I assumed it already was?
OK, I've made these changes...which makes me wonder if I've gone over the top with the generics in the first place
public interface IStatisticsHelper
{
void GenerateStatistics();
List<IStatistic> BuildReport();
}
...
public interface IStatisticsRepository<T> : IRepository<T>, IStatisticsHelper where T : IStatistic
{
}
...
public abstract class Statistic : Entity, IStatistic
{
protected abstract IStatisticsHelper Repository { get; }
...
public class AverageCheckTime : Statistic
{
protected override IStatisticsHelper Repository
{
get { return RepositoryFactory.AverageCheckTimeRepository; }
}
No, C# 3 does not support generic variance. C# 4 does, but you would have to declare that IStatisticsRepository is covariant in T:
public interface IStatististicsRepository<out T> : IRepository<T>
where T : IStastistic
Variance isn't safe in general - it depends on how the generic type parameter is used. C# 4 supports both covariance and contravariance for type arguments which are reference types, but only when the generic type involved is an interface or a delegate, and only when the type parameter is used in the appropriate way within the interface/delegate.
Without seeing the declaration for IRepository<T>, we can't tell whether or not it's safe. For example, if IRepository<T> contains a method like this:
void Save(string id, T value);
then it wouldn't be safe, because you'd be able to write:
IStatisticsRepository<IStatistic> repo = RepositoryFactory.AverageCheckTimeRepository;
IStatistic foo = new SomeOtherStastisticType();
repo.Save("Foo", foo);
That would be trying to save a SomeOtherStatisticType value in an AverageCheckTimeRepository, which violates type safety. It's only safe to make the interface covariant in T if values of type T only come "out" of the interface. (There are some wrinkles around exactly what that means, mind you...)
For a lot more information on this, see Eric Lippert's blog series on the topic.

Abstract class and interface with the same generic method

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

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