C# generic types - c#

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).

Related

How do I correctly constrain to related class type when using a generic method?

I have two base classes BaseObject and BaseObjectSettings. The first defines the object behaviour and the second defines the state of the class (useful for serialisation).
If I want to create a derived BaseObject class with specific settings then I can use a method with a generic type constraint.
public void CreateBaseObjectInstance<T>(BaseObjectSettings baseObjectSettings) where T : BaseObject
{
var instance = pool.GetInstance<T>();
instance.Settings = baseObjectSettings;
scene.Add(instance);
}
The problem I am facing is that while I can constrain the generic type to BaseClass I can't constrain the BaseClassSettings to the relevant derived BaseClass. This means that I can do things like
CreateBaseObjectInstance<Banana>(new AppleSettings());
which seems a bit terrible.
What are my options given that I am currently constrained to both creating and initialising the object in the same method before adding it to the scene?
One way is to have all your settings classes inherit from a generic base class. The generic base class could then inherit from BaseObjectSettings. The generic type parameter indicates what kind of object this settings class is for.
For example, for your AppleSettings,
class AppleSettings: ObjectSettings<Apple> {
...
}
abstract class ObjectSettings<T>: BaseObjectSettings where T: BaseObject {}
Now, you can change CreateBaseObjectInstance to accept an instance of ObjectSettings<T> instead:
public void CreateBaseObjectInstance<T>(ObjectSettings<T> objectSettings) where T : BaseObject
{
var instance = pool.GetInstance<T>();
instance.Settings = objectSettings;
scene.Add(instance);
}
If you pass Banana as T, it would expect ObjectSettings<Banana>, preventing you from giving it AppleSettings, which is ObjectSettings<Apple>.
You need to create a generic interface or base class that where you define the settings type:
public class BaseObject<TSettings>
{
public TSettings Settings { get; set; }
}
Then your method will require two generic arguments - one for the actual object to create TObject and one for method's argument for the settings TSettings. You then constrain TObject to an implementation of the implemented interface or base class/derivation thereof, using generic argument TSettings as the constraint's type's generic argument
public void CreateBaseObjectInstance<TObject, TSettings>(
TSettings settings
)
where TObject : BaseObject<TSettings>
{
...
}
Example (using above BaseObject implementation):
public class MyObjectSettings
{
...
}
public class MyObject : BaseObject<MyObjectSettigns>
{
}
Method call:
var settings = new MyObjectSettings(){ ... };
CreateBaseObjectInstance<MyObject>( settings ); // second generic argument should be inferred
I don't really understand the logic here as things are missing, but from the code provided you can probably write:
public void CreateBaseObjectInstance<TBase, TSettings>(TSettings baseObjectSettings)
where TBase : BaseObject
where TSettings : BaseObjectSettings
Used like that:
CreateBaseObjectInstance<Banana, AppleSettings>(new AppleSettings());
Can be improved to:
public void CreateBaseObjectInstance<TBase, TSettings>(TSettings baseObjectSettings)
where TBase : BaseObject
where TSettings : BaseObjectSettings, new()
{
if ( baseObjectSettings == null ) baseObjectSettings = new TSettings();
...
}
CreateBaseObjectInstance<Banana, AppleSettings>();
But if there is a strong coupling between entity and settings, you should redesign to define dependency with an association using a thing that can also be similar to #Sweeper's and #Moho's answers:
Association, Composition and Aggregation in C#
Understanding the Aggregation, Association, Composition
Generics in .NET
Generic classes and methods

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.

Property in generic base class with different implementation

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

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

Using Generics in C# - Calling Generic class from a Generic class

I have a class similar to the following:
public abstract class Manager<T, TInterface> : IManager<T> where TInterface : IRepository<T>
{
protected abstract TInterface Repository { get; }
public virtual List<T> GetAll()
{
return Repository.GetAll();
}
}
This works perfectly fine, however, is there a way to get away from having the TInterface in the abstract class declaration and in the resulting class that extends my generic abstract class:
public class TestManager : Manager<TestObject, ITestRepository>, ITestManager
I am forced to use ITestRepository and make the Repository property abstract due to the fact that it can contain custom methods that I need to know about and be able to call.
As I continue to build layers, I will have to keep doing this process the whole way up the stack. Examples would be if I had a generic abstract controller or service layer:
public class TestService : Service<TestObject, ITestManager>, ITestService
Is there a better way to do this or is this the best practice to allow a generic class to call another generic class?
It seems that all you want to do is to make Manager<T> testable, and use a mock as a repository that you can query for special members.
If that's the case, maybe you can change your design to this:
public class Manager<T> : IManager<T> {
protected IRepository<T> Repository { get; set; }
// ...
public virtual List<T> GetAll() {
return Repository.GetAll();
}
}
Now, all the specifics of testing are in a testing subclass:
public class TestingManager<T> : Manager<T> {
public new ITestRepository<T> Repository {
get {
return (ITestRepository<T>)base.Repository;
}
set {
base.Repository = value;
}
}
}
When you write your unit tests, you create TestingManager<T> instances (referenced through TestingManager<T> declared variables and fields), and you provide them with a test repository. Whenever you query their Repository, you'll always get a strongly-typed test repository.
UPDATE:
There's another way to solve this, without a subclass. You declare your repository objects as test repositories that you pass to Manager<T>s and you query them directly, without going through the Manager<T>.
[Test]
public void GetAll_Should_Call_GetAll_On_Repository_Test() {
var testRepository = new TestRepository();
var orderManager = new Manager<Order>(testRepository);
// test an orderManager method
orderManager.GetAll();
// use testRepository to verify (sense) that the orderManager method worked
Assert.IsTrue(testRepository.GetAllCalled);
}
No, you can't get around it. You can try, but the result will be ugly and in some way incorrect. The reason is that you are asking generics not to be generic but still be generic.
If a new class uses a generic class, either in inheritance or composition, and it itself does not know enough to specify the type parameters to the generic class it is using, then it must itself be generic. It is analogous the method call chains, where a method may pass parameters along to another method. It can't make up the arguments to the inner method, but must rather take them as parameters itself from a caller that does know what they are. Type parameters are the same.
One thing that does make this feel like code smell is the fact that you can't have a variable of type Manager<,>. It has to be fully type-specified. One solution I've come up with is to have non-generic interfaces that the generic classes implement. These interfaces have as much of the public interface of the generic class as is possible (they can't have methods or properties that reference the type parameters). Then you can pass around variables of the type of the interface and not have to specify type parameters.
Example:
interface IExample {
string Name { get; }
void SomeNonGenericMethod(int i);
}
class Example<T> : IExample {
public string Name { get { ... } }
public void SomeNonGenericMethod(int i) {
...
}
public T SomeGenericMethod() {
...
}
}

Categories