Property in generic base class with different implementation - c#

I've got an abstract class CommandBase<T, X> that I want to have a property InnerCommand.
But since the InnerCommand might have other types for T and X than the command that contains it, how can I define that?
The abstract class:
public abstract class CommandBase<T, X>
where T : CommandResultBase
where X : CommandBase<T, X>
{
public CommandBase<T, X> InnerCommand { get; set; }
(...)
}
In the example above InnerCommand will only accept instances that have the same types for T and X, but I need to allow for other types.
An AddOrderitemCommand:
public class AddOrderitemCommand : CommandBase<AddOrderitemResult, AddOrderitemCommand>
{
(...)
}
Might contain a WebserviceCommand:
public class GetMenuCommand : CommandBase<GetMenuResult,GetMenuCommand>
{
(...)
}
Please advise on the syntax for allowing this.

You basically have three options:
Use dynamic as the type of that property. Nothing I would do.
Use object as the type of that property. Nothing I would do.
Create a non-generic base class or interface for commands. Make CommandBase<T, X> implement it and use it as the type of the property. That's the way I would go.

If the InnerCommand doesn't relate to the parent T/X, then I would suggest using a non-generic InnerCommand that doesn't advertise the type in the signature. This may mean adding a non-generic base-type (CommandBase) or an interface (ICommandBase). Then you can simply use:
public ICommandBase InnerCommand {get;set;}
// note : CommandBase<T,X> : ICommandBase
or
public CommandBase InnerCommand {get;set;}
// note : CommandBase<T,X> : CommandBase

Related

Inheritance of nested generics / nested generics in abstract class C#

I have two abstract classes that can be inherited for explicit usage: A_GUI_Info and A_Info_Data. The GUI_Infos are GUI elements that display data. The Info_Datas are data classes, that transfer specific data to the according GUI_Info.
I want to express the dependency that an explicit GUI_Info has one explicit Info_Data through generics and still allow an inheritance. With other words, I want to avoid that a wrong explicit Info_Data is fed to an explicit GUI_Info. For example, I feed HUD_Info_Data to a Wrist_GUI_Element that does not have the means to represent it. > A kind of type-safety for inherited generics
Example:
class HUDInfoData : A_Info_Data
class HUDInfo<HUDInfoData > : A_GUI_Info<A_Info_Data>
// but the generic cant be inherited like that
class HUDInfo : A_GUI_Info<A_Info_Data>
// doesnt define dependency
class HUDInfo : A_GUI_Info<HUDInfoData >
// also not working
Another approach is restrictions by where T : A_GUI_Info<D> where D : A_Info_Data But it did not work like that.
The final requirement, that I cant get to work is: I have an instance of the explicit Info and want to handle it in a function, that could also handle all other inherited Infos with their according Datas.
public HUD_Info<HUD_Info_Data> obj;
public List<A_GUI_Info<A_Info_Data>> infos;
public void SetConnection(string ID, A_GUI_Info<A_Info_Data> p)
{
infos.Add(p);
}
It may end up that you need to use this kind of data structure:
public abstract class A_GUI_Info<G, D>
where G : A_Info_Data<G, D>
where D : A_GUI_Info<G, D>
{
public G Gui { get; set; }
}
public abstract class A_Info_Data<G, D>
where G : A_Info_Data<G, D>
where D : A_GUI_Info<G, D>
{
public D Data { get; set; }
}
It's not overly nice, but it does tie the two derived types to each other.
You would defined them like this:
public class HUDInfoData : A_Info_Data<HUDInfoData, HUDInfo>
{
}
public class HUDInfo : A_GUI_Info<HUDInfoData, HUDInfo>
{
}
Have you tried:
abstract class A_Info_Data { ... }
abstract class A_GUI_Info<T> where T: A_Info_Data { ... }
And now:
class CriticalData: A_Info_Data { ... }
class CriticalGui: A_GUI_Info<CriticalData> { ... }
The type parameter on the base class only exists on the base class. The more derived class has to define a new type parameter and pipe through the type to the base class's type parameter. This gives you a place to pose more generic constraints.
For example:
class HUDInfo<THudInfoData> : A_GUI_Info<THudInfoData> where THudInfoData : A_Info_Data
Now, HUDInfo<> can take any HudInfoData as long as it derives from A_Info_Data (or if it is A_Info_Data). If you wanted to have HUDExtremelySpecificInfo which could only take HUDExtremelySpecificInfoData, that would look like:
class HUDExtremelySpecificInfo<THudInfoData> : A_GUI_Info<THudInfoData>
where THudInfoData : HUDExtremelySpecificInfoData
If you never want to specify the type because you know that it will always be HUDExtremelySpecificInfoData, you can also declare either both:
class HUDExtremelySpecificInfo<THudInfoData> : A_GUI_Info<THudInfoData>
where THudInfoData : HUDExtremelySpecificInfoData { .. }
class HUDExtremelySpecificInfo : HUDExtremelySpecificInfo<HUDExtremelySpecificInfoData> { .. }
(where you implement the non-generic HUDExtremelySpecificInfo in terms of the generic HUDExtremelySpecificInfo<>, and can use the generic one if there's a specific even more extremely specific info data subclass that you want to specify)
or just one:
class HUDExtremelySpecificInfo : A_GUI_Info<HUDExtremelySpecificInfoData> { .. }
Thank you all for giving constructive answers. What I try here is not working like preferred (pbbly not possible at all). This is what I came up with:
// abstract definitions
public abstract class AInfo
{
public abstract void SetData(AInfoData data);
}
public abstract class AInfoData
// explicit definitions
public class WristInfo : AInfo
{
public override void SetData(AInfoData data)
{
Data_Info_Wrist d = (Data_Info_Wrist)data; // cast to use
}
}
public class Data_Info_Wrist : AInfoData
// runtime usage
public AInfo instance; (WristInfo)
public void Setup(AInfo info) { }
For Unity workflow I require the explicit class to be non-generic. So this workaround is possibly the best solution. The drawback: The desired type-safety is not given here.

Compiler Issue with Generics and Inheritance

I have 2 classes with the following declarations:
abstract class ClassBase<T, S> where T : myType where S : System.Data.Objects.DataClasses.EntityObject
abstract class ServiceBase<T> where T : myType
and I have 2 other classes, that inherit one from each, we can call ClassInherited and ServiceInherited. Note that the two Service classes are not in the same project as the other two.
The idea is that in the ServiceBase class I can declare a property like protected ClassBase<T,System.Data.Objects.DataClasses.EntityObject> Class { get; set; } and then in the inherited service`s constructor something like this.Class = ClassInheritedInstance
I already implemented the idea but it gives me this error when assigning the Class property in the ServiceInherited class constructor:
Cannot implicitly convert type 'ClassInherited' to 'ClassBase< T, S>'
Note that ClassInherited is indeed an specification of Class<T,S>... it's just that the compiler doesn't seem to be able to tell the types correctly. Also changing the declaration of the class property to protected ClassBase<T, EntityObjectInherited> works, and EntityObjectInherited is an implementation of System.Data.Objects.DataClasses.EntityObject... I don't see why is there a problem.
Update 1
Note that at compile time the type of ClassInherited is known, as its declaration is public class ClassInherited : ClassBase<myTypeInherited, EntityObjectInherited>
INITIAL ANSWER
The reason that you cannot use protected ClassBase<T,S> Class { get; set; } in the ServiceInherited-class is that you do not know the S-type that is needed to declare a type of the property Class.
You have to options:
Include the S type in the specification of the Service-type: abstract class ServiceBase<T, S> where T : myType where S : System.Data.Objects.DataClasses.EntityObject
Implement an interface for ClassBase with only the T-type, so that you can refer to a class-inherited-object without using the S-type. Then you CAN have a property in the service class (of the interface-type), since you do not need to specify the S-type.
Note that generic-type-checking is not checked at run-time, but at compile-time. Else it wouldn't be strong-typing.
UPDATE
The reason the cast won't work is that type ClassBase<T, EntityObjectInherited> is not equal or castable to ClassBase<T, System.Data.Objects.DataClasses.EntityObject>. Covariance doesn't work on class-types, only on interface-types.
I think the solution here is to work with interfaces. Use an interface for class-base, say IClassBase<T>. That way you can omit the S-type in the signature of the class, and only have it in the interface.
UPDATE (2)
One thing you can do is to create an interface for the Class property. You can define the following interface.
public interface IClass<T> where T : myType {
// TODO
// Define some interface definition, but you cannot use the
// EntityObject derived class, since they are not to be known
// in the service class.
}
If you implement this interface on your ClassBase class, and add a constructor on your ServiceBase class which accepts an object of type IClass, then you can push this object to property Class in the base-class. Like this:
public abstract class ClassBase<T, S> : IClass<T>
where T : MyType
where S : EntityObject {
}
public abstract class ServiceBase<T> where T : MyType {
protected ServiceBase(IClass<T> classObject) {
Class = classObject;
}
protected IClass<T> Class { get; set; }
}
public class ServiceInherited : ServiceBase<MyTypeDerived> {
public ServiceInherited(IClass<MyTypeDerived> classObject)
: base(classObject) {
}
}
One thing to note, is not to expose the S-type of the ClassBase to the interface. Since you do not want the Service-classes to know this type, they cannot actively call any methods or use properties that somehow have the S-type in their definition.
This ugly boxing, unboxing should work :
Class = (ClassBase<T, S>)(object)new ClassInherited();
Covariance is allowed only with generic interface today ?MSDN
This works :
// Covariance.
IEnumerable<string> strings = new List<string>();
// An object that is instantiated with a more derived type argument
// is assigned to an object instantiated with a less derived type argument.
// Assignment compatibility is preserved.
IEnumerable<object> objects = strings;
This doesn't :
List<string> strings = new List<string>();
List<object> objects = strings;
The compiler won't be able to guess that ClassInherited is indeed a correct match for ClassBase<T, S> as it does not know the exact types of T and S, that will be decided at generics type instanciation at runtime.
So if you're sure that at runtime the types will be compatible you can safely try a cast :
Class = ClassInheritedInstance as ClassBase<T, S>
This will only have a slight (not to say negligible) overhead as the CLR will need to check the compatibility of the types to have safe code.

C# generic types

I use in my library three classes:
public abstract class Base<TFirst, TSecond>
{
public Base()
{
// actions with ID and Data of TFirst and TSecond
}
}
public abstract class First<TFirstID, TFirstData>
{
public TFirstID ID {get; set;}
public TFirstData Data {get; set;}
}
public abstract class Second<TSecondID, TSecondData>
{
public TSecondID ID {get; set;}
public TSecondData Data {get; set;}
}
How can I specify that TFirst must inherit from the First and TSecond must inherit from the Second, not using generic types for ID and Data in Base?
Like this:
public abstract class Base<TFirst, TSecond>
where TFirst : First // without generic-types
...
Edit:
In classes First, Second I use TFirstID and TSecondID for properties. In class Base I use this properties.
There's no way you can do this other than by introducing a parallel class hierarchy without geherics and doing some runtime checks:
public abstract class Base<TFirst, TSecond>
where TFirst : First
{
static Base()
{
if(!typeof(TFirst).IsGenericType ||
typeof(TFirst).GetGenericTypeDefinition() != typeof(First<,>))
throw new ArgumentException("TFirst");
}
}
public abstract class First { }
public abstract class First<TFirstID, TFirstData> : First
{
}
Alternatively, you can replace First with a marker interface (IFirst).
The runtime check is possible due to the fact that static constructors are invoked for each closed generic type.
Usually in a case like this, I'll build another base class (non-generic) for First<TFirstID, TFirstData> to derive from, so:
public abstract class First{}
public abstract class First<TFirstID, TFirstData>
: First
{
}
Then you can put a where TFirst : First into your declaration. It's not perfect, but it works if you're careful. But it can be tricky, depending on what you're trying to accomplish - you lose all of the genericness of the restricted type.
One solution would be to have First and Second themselves implement an interface that doesn't depend on the generic type parameters:
public interface IFirst
{
}
public abstract class First<TFirstID, TFirstData> : IFirst
{
}
Then ensuring that the type parameter in base must use IFirst
public abstract class Base<TFirst, TSecond>
where TFirst : IFirst
That can be tricky if they are dependent on signatures with those items. I'd probably say create an interface or abstract base without the type signatures. Interface more likely.
That's the way you would do it, if at all possible; specify generic type constraints which allow the compiler to catch invalid usages of Base's generic parameters.
If, for some reason, you couldn't use generic type constraints at all, the only other way to enforce type-checking would be to add run-time checks to your logic that would throw an exception if the generic was created specifying invalid generic types:
public abstract class Base<TFirst, TSecond>
{
public Base()
{
if(!typeof(TFirst).IsAssignableFrom(typeof(First))
throw new InvalidOperationException("TFirst must derive from First.");
if(!typeof(TSecond).IsAssignableFrom(typeof(Second))
throw new InvalidOperationException("TSecond must derive from Second.");
}
}
The above code is a serious code smell. The whole point of generics is to allow a class to work with many different internal classes, while allowing the compiler to ensure that the parameter types used are such that the generic class can work with them. And besides, you still have to be able to reference the namespace of First and Second (which I assume is the reason you can't use them as generic type parameters in the first place).

How to use the "where" keyword in C# with a generic interface, and inheritance

What I want to achieve is this:
Declare a generic class (<T>),
Have the "T" restricted to types that implement IMySpecialInterface<X> (where "X" is not a known type),
And have the class inherit from a parent class.
to give an incorrect example:
public class MyClass<T> : MyParentClass where T : IMySpecialInterface<X>
{
...
}
What is the proper syntax to achieve this?
Thanks.
You can't use generics without knowing the types, unless you created the type at runtime.
Your best fit would be:
public class MyClass<T, U> : MyParentClass where T: IMySpecialInterface<U>
{
}
UPDATE or could you potentially use dynamic?
You will need to define a non-generic version of IMySpecialInterface<X>, unless you supply a secondary type for MyClass. The whole thing would look like this then:
public interface IMySpecialInterface
{
}
public interface IMySpecialInterface<X> : IMySpecialInterface
{
}
public MyClass<T> : MyParentClass where T : IMySpecialInterface
{
}
public class MyClass<T, X> : MyParentClass where T : IMySpecialInterface<X>
{
...
}

How do I declare the constructor for a generic class with a non-generic base class with parameters

I have a base class which is non-generic with a derived generic class. The AbstractRepository and ILoggingManager are provided by the IoC framework.
Base Class
public abstract class EventHandlerBase
: AbstractDataProvider
, IEventHandler
{
public EventHandlerBase(
AbstractRepository data,
ILoggingManager loggingManager
)
: base(data, loggingManager)
{
}
}
Derived Class
public abstract class EventHandlerBase<TDetail>
: EventHandlerBase
where TDetail : Contracts.DeliveryItemEventDetail
{
}
I would like to declare a constructor in the derived class that will call the non-generic base class, but I do not know the syntax.
Should it not be more like:
public abstract class EventHandlerBase<TDetail> : EventHandlerBase
where TDetail : Contracts.DeliveryItemEventDetail
{
public EventHandlerBase(AbstractRepository data, ILoggingManager loggingManager)
: base(data, loggingManager)
{
// Initialize generic class
}
}
public class EventHandlerBase(AbstractRepository data,
ILoggingManager loggingManager)
: base(data, loggingManager)
{
// Whatever
}
should work fine. If it doesn't, could you show the problems you're getting?
EDIT: I think the whole base class thing may be clouding the issue here. When you declare a constructor in a generic type, you don't specify the type parameters. For example, List<T> would look something like:
public class List<T>
{
public List()
{
}
}
The idea is that within the class declaration, T is already known - you only specify type parameters when you want to add more of them, e.g. for a generic method like ConvertAll.

Categories