Generic base class where T is also a generic base class - c#

I have a generic base class something like:
public abstract class SomeThingBase<T> where T : class
I'd like to have another base class something like this:
public abstract class MangerBase<T> where T : SomeThingBase<T>
How do you accomplish this in C#?
When trying to use ManagerBase like this it doesn't seem to work.
class TestManager : ManagerBase<TestSomething>

In order to do this you have to pass your generic declarations in all the way from the top. This can get very messy, so avoid doing it.
public abstract class SomeThingBase<T> where T : class{ }
public abstract class ManagerBase<T, U>
where T : SomeThingBase<U>
where U : class
{ }

It's definitely possible to define, but impossible to actually implement. Assuming you have the below definition:
public abstract class SomeThingBase<T> where T : class { }
public abstract class MangerBase<T> where T : SomeThingBase<T> { }
However, defining a class that implements ManagerBase<T> and SomethingBase<T> is impossible since multiple inheritance is not supported and T cannot meet both constraints without multiple inheritance the generic type.

Related

How to pass child type to generic in parent class C#

I am currently consuming a third party dll and have no option to switch off of it or not use it. I have a class that looks like this:
public abstract class ParentClass<T> : ApiClass<T> where T : ApiClass<T>
{
//...stuff
}
This causes a few problems if I want to make a Dictionary or return the ParentClass type so that I don't need to know which child class it is beforehand. To make it easier to develop around this I would like to do something like this:
//ChildClass should be what is passed to the generic, without directly referencing it
public abstract class ParentClass : ApiClass<InheritedClass>
{
//...stuff
}
public class ChildClass : ParentClass
{
}
//Now I could define a dictionary like
Dictionary<KeyClass, ParentClass> Map;
Defining it like the second example would allow me to create a Dictionary as where the first one I'm not sure I can define a Dictionary when I don't have a value for the Generic? A bit more info about the ApiClass, the definition for the ApiClass looks like this:
public abstract class ApiClass<Wrapper> : OtherApiClass where Wrapper : ApiClass<Wrapper>
{
//...Stuff
}
So in a scenario like this, how would I define my ParentClass without a Generic, but where the type passed to ApiClass is the child class of the ParentClass (the ApiClass explicitly needs the child type)?
Edit: Clarified a bit on the value of InheritedClass
Edit2: I am not looking for alternatives, I am asking for how to. If I pass anything other than the last inherited class (the current ParentClass I defined at the beginning of the question) the Api will crash. If the syntax existed it would look something like
public abstract class ParentClass : ApiClass<typeof(this)>
I imagine that the third-party library you're using defines ApiClass like this:
public abstract class ApiClass<T> where T : ApiClass<T>
That's an example of the Curiously recurring template pattern.
Let's turn this in to a concrete example:
public abstract class ApiClass<T> where T : ApiClass<T>
{
public abstract T GetNewInstance();
}
If I had that code, I could consume it like this:
public class MyApiClass : ApiClass<MyApiClass>
{
public override MyApiClass GetNewInstance()
{
return new MyApiClass();
}
}
This allows MyApiClass to have an method, defined as an abstract method in that parent class, that knows about the current instance. Eric Lippert discusses this here.
It has the downside that it can be abused:
public class MyNefariousApiClass : ApiClass<MyApiClass>
{
public override MyApiClass GetNewInstance()
{
throw new NotImplementedException();
}
}
That's legal, but C# doesn't have a way of enforcing that you use class itself as the generic parameter. If we had class MyNefariousApiClass : ApiClass<this> it would, but we don't.
Now, when you say you have a class public abstract class ParentClass<T> : ApiClass<T> where T : ApiClass<T> that that's your code for consuming the third-party library.
If so, then that's not the normal way to consume this pattern. If you're overriding the class it should look like this:
public abstract class ParentClass<T> : ApiClass<T> where T : ParentClass<T>
We can then take this to it's final point and define the ChildClass like so:
public class ChildClass : ParentClass<ChildClass>
{ }
Now, if you want a dictionary that can hold any such ChildClass then you are stuck as the parent is generic. The only somewhat sensible workaround is to use an interface.
public interface IParent
{ }
public abstract class ParentClass<T> : ApiClass<T>, IParent where T : ParentClass<T>
{ }
Then you can write Dictionary<KeyClass, IParent> dictionary = new ....

Collection Inheritance

I am trying to achieve the following, however I am not sure if it is even possible.
I have the following 'base' entities
public abstract class BaseObject {}
public abstract class BaseCollection <T> : ObservableCollection<T> where T : BaseObject {}
I also have
public class Obj_1: BaseObject {}
public class Obj_1_collection : BaseCollection <Obj_1>
{
public Obj_1_Method_1 () {}
}
and
public class Obj_2: Obj_1 {}
Following the same logic as Obj_1, I want to have a Obj_2_collection. I want this collection to inherit from Obj_1_collection in order to access its methods e.g. Obj_2_collection.Obj_1_Method_1(). As I have it in my mind I am trying to do something like the following (in pseudocode):
public class Obj_2_collection : Obj_1_collection<Obj_2 extends Obj_1>
meaning that the Obj_2_collection can access Obj_1_collection, however the collection object it will be of type Obj_2
You're nearly there, your only problem is that you didn't define your Obj_1_collection as a generic.
To do so, you just have to use the syntax you used for the BaseCollection<T> and restrict the type T to Obj_1
That would give :
public class Obj_1_collection<T> : BaseCollection <T> where T : Obj_1 {}
Concerning the use of generics and the inheritance, you might want to read about the in and out modifiers keyword to enable covariance and contravariance.
As a side note, here are the C# naming conventions

C# Derive From Generic Base Class (T : U<T>)

I am trying to find a way to derive a class from a generic base class. Say:
sealed public class Final : Base<Something>
{
}
public class Base<T> : T
where T : Anything // <-- Generics do not allow this
{
}
In C# this does not seem to be possible.
Is there any other solution to achieve something similar to this?
I found this StackOverflow question, but it doesn't seem to solve the issue, or at least I do not understand how it should.
EDIT:
The result I'd like to get is to be able to do something like that:
Anything[] anything;
//Assign some Instances to anything
foreach(Final final in anything){
//do something with final
}
The result I'd like to get is to be able to do something like that:
Anything[] anything;
//Assign some Instances to anything
foreach(Final final in anything){
//do something with final
}
Your foreach loop suggests this: class Anything : Final { … }.
This obviously turns around the inheritance hierarchy as you planned and named it. (You cannot have cycles in your inheritance relationships).
public class Base<T> : T where T : Anything { …
Let me elaborate on this part for a bit. I'll reduce your example even further to just class Base<T> : T.
This is not possible, for good reason. Imagine this:
class Base<T> : T
{
public override string Frobble()
{
Fiddle();
return "*" + base.Frobble() + "*";
}
}
class A
{
public sealed string Frobble() { … }
}
class B
{
}
class C
{
public virtual string Frobble() { … }
}
abstract class D
{
public abstract void Fiddle();
public virtual string Frobble() { … }
}
class E
{
public void Fiddle() { … }
public virtual string Frobble() { … }
}
You get all kinds of absurd situations if class Base<T> : T were allowed.
Base<A> would be absurd because Frobble cannot be overridden in a derived class.
Base<B> would be absurd because you cannot override a method that
doesn't exist in the base class.
Base<C> doesn't work because there is no Fiddle method to call.
Base<D> would not work because you cannot call an abstract method.
Only Base<E> would work.
How would the compiler ever know how to correctly compile Base<T> and analyse code that depends on it?
The point is that you cannot derive from a class that is not known at compile-time. T is a parameter, i.e. a variable, a placeholder. So class Base<T> : T is basically like saying, "Base<T> inherits from some (unknown) class". Class inheritance is a type relationship that requires both involved types to be known at compile-time. (Actually, that's not a super-precise statement because you can inherit from a generic type such as class SpecialList<T> : List<T>. But at the very least, the derived class has to know what members (methods, properties, etc.) are available in the base class.)
Is this what you want?
sealed public class Final : Base<int>{
}
public class Base<T> {
}
You could only do this if Final would be a generic class as well, like so:
public sealed class Final<T> : Base<T>
Then you can put a type restraint on T as either a class, to allow only reference types as T, or an instance of Base<T>, to allow only types that derive from Base<T>:
public class Base<T> where T : Base<T>
I don't know the context of this question, but I ran into same question with a project where I had to make it possible to extend the base class which is already derived by many others. Like:
abstract class Base {}
class FinalA : Base {}
class FinalB : Base {}
// Now create extended base class and expect final classes to be extended as well:
class BetterBase : Base {}
The solution was to create common ancestor and connect through properties:
abstract class Foundation {}
abstract class Base : Foundation
{
Foundation Final { get; }
}
class FinalA : Foundation {}
class FinalB : Foundation {}
class FinalC : Foundation
{
Foundation Base { get; }
}
// Here's the desired extension:
class BetterBase : Base {}
Now BetterBase has connection to final class and if needed, the final classes could have connection with (Better)Base also, as shown in FinalC class.

Constraints on Type Parameters for object and list of objects

Is there a way to implement constraint type parameters where T is from a base class or if T is a list containing the "base class"?
Something looking like this :
public class SomeClass<T> where T : MyBaseClass, IList<MyBaseClass>
No, you can't create generic constraint to work like OR.
And just to point that that kind of constraint would have been useless: you would not be able to use neither methods defined in BaseClass nor these from IList (because T could have been the first or the second).
No but you could have overloaded methods that take one or the other:
public class SomeClass<T> where T : MyBaseClass
{
public void Process(T instance)
{
}
public void Process(IList<T> list)
{
}
}
Why don't you implement an interface on the BaseClass and do.
public class SomeClass<T> where T : class, IBaseInterface
This also guarantees that the children are implementing the appropriate contracts that you want to expose.

How can I make a class both implement an Interface and inherit from another class

I want my class to implement an interface and also get the additional properties from Auditable table. Can I do both? I have tried to do it here but I am getting an error in my IDE.
public partial class ObjectiveDetail : IEquatable<ObjectiveDetail>, AuditableTable
{
...
}
public abstract class AuditableTable : IAuditableTable
{
...
}
You must change
public partial class ObjectiveDetail : IEquatable<ObjectiveDetail>, AuditableTable
to
public partial class ObjectiveDetail : AuditableTable, IEquatable<ObjectiveDetail>
In C#, you can inherit one class and implement multiple interfaces and you must put class first.
public SubClass : BaseClass, IInterface
Yes you can do both, but you have to put the base class first:
public partial class ObjectiveDetail : AuditableTable, IEquatable<ObjectiveDetail>
Base class first and then Interface, should work
Nothing prevents you from both implementing an interface and inheriting from a class in the same class, C# only doesn't support multiple inheritance (inheriting from multiple diferent classes) so you don't need to do anything, it should just work.

Categories

Resources