generic of generic - c#

I've a generic base class where generic type is class and other related inherited class:
public class BaseClass<T> where T : class
{
virtual void DoWork(){..}
virtual void DoAnotherWork(){..}
}
public class SomeInherit<Person> : BaseClass<Person>
{
//...
}
public class OtherInherit<Car> : BaseClass<Car>
{
// override something..
}
Then, I've a BaseClassManager which should be able to load some BaseClass inherited by some co-worker via reflection:
public class BaseClassManager
{
public BaseClass<TItem> LoadBaseClass<T>() where T : BaseClass<???>
{
// how can create an instance of T?
// TItem : class
// T : BaseClass
// -------------> in reality, it should be: T<TItem> (just as BaseClass<Person>)
}
}
Is there any way to accomplish that..?

You need to define a second type parameter for where T : BaseClass<???>.
You can use the new() constraint to allow the method to create instances of a generic type.
public TBaseClass LoadBaseClass<TBaseClass, TItem>()
where TBaseClass : BaseClass<TItem>, new()
where TItem : class
{
return new TBaseClass();
}
Usage:
SomeInherit<Foo> result = LoadBaseClass<SomeInherit<Foo>, Foo>();

Related

What is the best way to call a method defined inside an abstract generic class from a non generic class

I don't want to make class B generic because there lots classes inheriting from class B. How to use the method "GetSomeData" of the generic class "classA" in a non generic class?
Here's my code:
public abstract class classA<T> : IInterface<T>
where T : new()
{
public String GetSomeData (Guid ID)
{
return somestring;
}
}
public abstract class ClassB : InterfaceB
{
//Use GetSomeData(Guid ID) here
}
what is the best way to invoke GetSomeData in class B?
First of all, your code doesn't look clean itself. C# coding conventions are not met & not all the components that are used present.
But to anser your question, you need to specify the concrete type T before using generic methods/classes.
For example working code may look like this:
public abstract class GenericParent<T>
where T : new()
{
public string GetSomeData(Guid id) => string.Empty;
}
// Non abstract type, to create be able to create an instance
public class GenericChild<T> : GenericParent<T> where T : new()
{
}
public abstract class ClassB
{
public void DoSomething()
{
// Creating instance of a generic type, specifying concrete T (in this case of type SomeClass)
var instance = new GenericChild<SomeClass>();
instance.GetSomeData(Guid.Empty);
}
}
// An example of type, that meets the "where" condition of T in the generic type
public class SomeClass
{
}
As per OOP principals Abstract classes can not be instantiated.
They could only be Inherited. Well there are couple of ways how you can access the instance variables and methods from the Abstract class as follows.
Make a sub-class inheriting the Abstract class; Create an object of sub-class and access all the Instance Variables and Methods.
public abstract class classA<T> : IInterface<T>
where T : ITask, new()
{
public String GetSomeData (Guid ID)
{
return somestring;
}
}
public class ChildOfClassA : ClassA<SomeType_of_Type_ITask>
{
}
public abstract class ClassB : InterfaceB
{
//Use GetSomeData(Guid ID) here
ChildOfClassA obj = new ChildOfClassA();
string result = obj.GetSomeData(Guid.NewGuid());
}
Make that method Static if its not tightly coupled to instance of the class. and then you can use it with ClassName.MethodName
public abstract class classA<T> : IInterface<T>
where T : ITask, new()
{
public **static** String GetSomeData (Guid ID)
{
return somestring;
}
}
public abstract class ClassB : InterfaceB
{
//Use GetSomeData(Guid ID) here
string result = classA.GetSomeData(Guid.NewGuid());
}
You can inherit this Abstract class in the class you want to use it and directly access it by base.MethodName or directly MethodName.
public abstract class classA<T> : IInterface<T>
where T : ITask, new()
{
public string GetSomeData (Guid ID)
{
return somestring;
}
}
public abstract class ClassB : ClassA<SomeType_of_Type_ITask>, InterfaceB
{
//Use GetSomeData(Guid ID) here
string result = [base.]GetSomeData(Guid.NewGuid()); //[base.] is optional even you can override this function or overload it.
}
In case 1 and 3 you will have to pass generic argument in order to inherit the Abstract class as in your case Abstract class accepts generic arguments.

How to create an instance of a Generic class where type constraints to same generic class

Suppose a class defined as below,
public class MyGeneric<T> where T : MyGeneric<T>
{
}
Can we create an object of this class? If not, why does this exist?
I'm asking this of my curiosity and don't have an in depth knowledge in C#.
It's useful when you have a class hierarchy, and you want to be able to write methods in the base class which return instances of the derived class (such as this):
public abstract class Base<T> where T : Base<T>
{
public T WithFoo(int foo)
{
// ...
return (T)this;
}
}
public class Derived : Base<Derived>
{
// ...
}
Derived d = new Derived().WithFoo(3);
Of course, this doesn't stop someone from writing:
public class Other : Base<Derived> { }
... and the only way to get around this is with a runtime check, which can be ugly:
public Base()
{
Trace.Assert(typeof(T) == this.GetType());
}
Some other languages have specific keywords to cover this case.
You can do it by inheriting from MyGeneric:
public class MyGeneric<T> where T : MyGeneric<T>
{
}
class MyGenericChild : MyGeneric<MyGenericChild>
{
}
var myGenericChild = new MyGenericChild();
var myGeneric = new MyGeneric<MyGenericChild>();
This is helpful when there is need to create type-specific members in the base class, specific to the actual descendant.
public class MyGeneric<T> where T : MyGeneric<T>
{
public void Do(T t)
{
...
}
}
class MyGenericChild : MyGeneric<MyGenericChild>
{
// Do for MyGenericChild will accept only MyGenericChild and it's descendants
}

Derived classes with derived properties

I have 2 classes that are both derived from a base class X. The base class contains a property of a class T. Both subclasses of X should contain a property that's derived from T.
What I would like to achieve is to declare the a property of T in the base class X and have it used in several methods, while using the same property of T in the derived classes of X but have it recognized as a derived class from T, so that I won't have to cast it every time I want to use it.
One of my solutions would be just remove the property from the base class and copy the methods for each derived class of X, but that would defeat the purpose of using inheritance.
Is anything like that achievable?
internal class TestObject
{
public string ID;
public XObject obj;
//....
}
internal class TestDocument : TestObject
{
public XDocument obj; //<--- want to be able to call obj in my methods
//as if it were an XDocument type but relate to the obj property in the base class
//....
}
internal class XObject
{
//....
}
internal class XDocument : XObject
{
//....
}
Generics should work for you:
class Base<T> where T: MyType
{
T MyProperty { get; set; }
public void DoSomething()
{
// do something with MyProperty
}
}
with MyType being the base-class of the property within Base.
Then in your derived class you can define the generic constraint, e.g.
class Derived : Base<DerivedType>
{
}
Now an instance of Derived has the property MyProperty of type DerivedType instead of MyType.
So in your case TestObject should be similar to this:
internal class TestObject<T> where T: XObject
{
public string ID;
public T obj;
//....
}
internal class TestDocument : TestObject<XDocument>
{
// obj is here of type XDocument
}
Make the type of the property a generic parameter of your base class:
class PropertyTypeBase { }
class PropertyTypeA : PropertyTypeBase { }
class Base<T> where T : PropertyTypeBase
{
public T Property { get; }
}
class Foo : Base<PropertyTypeA>
{
public Foo()
{
PropertyTypeBase x = Property;
PropertyTypeA a = Property;
}
}
The simplest way would be to make the base class generic, and constrain the generic parameter to be derived form a certain class:
class BaseProp { }
class DerivedPropA: BaseProp { }
class DerivedPropB : BaseProp { }
abstract class X<T>
where T: BaseProp
{
public T Value { get; set; }
public abstract void With(T value);
}
class A : X<DerivedPropA>
{
public override void With(DerivedPropA value)
{
this.Value = value;
}
}
class B : X<DerivedPropB>
{
public override void With(DerivedPropB value)
{
this.Value = value;
}
}
This is possible by using generics.
First, let me explain the example classes. Let's say these are your properties:
public class BaseHead {}
public class OrganicHead : BaseHead {}
public class CyborgHead : BaseHead {}
And you now want to implement these heads on your person classes:
public class BaseCreature {}
public class OrganicCreature : BaseCreature {}
public class CyborgCreature : BaseCreature {}
The solution:
public class BaseCreature<THead> where THead : BaseHead
{
public THead Head { get; set; }
public BaseCreature(THead head)
{
this.Head = head;
}
}
We make the BaseCreature generic
We limit the THead type to only allow types that either are BaseHead or are derived from BaseHead
However, we also want to ensure that the right creature (organic/cyborg) only uses the correct head (organic/cyborg). This can be done by deriving from a BaseCreature with a specific generic type:
public class OrganicCreature : BaseCreature<OrganicHead>
{
public OrganicCreature(OrganicHead head) : base(head)
{
}
}
CyborgCreature is analogous.
Suppose you wanted to make it possible that every creature can use every type of head. If that's what you want, then you need to keep the generic parameter generic:
public class OrganicCreature<THead> : BaseCreature<THead> where THead : BaseHead
{
public OrganicCreature(THead head) : base(head)
{
}
}
CyborgCreature is analogous.

C# inherited class from generic as a type

I've got an issue with generics. I've those classes :
abstract class BaseTestClass<T> : where T : class, new()
{
//base test class implementation
public abstract void Run(BaseDataClass<T> data);
}
class BaseDataClass<T> : where T : class, new()
{
//base data class implementation
}
class DataA : BaseDataClass<SettingsA>
{
//some stuff
}
class TestA : BaseTestClass<SettingsA>
{
//Works!
public override void Run(BaseDataClass<SettingsA> data)
{
}
//Doesn't Work!
public override void Run(DataA data)
{
}
}
My question if why can't I use the inherited class in the abstract method ?
[EDIT]
The error at compilation is:
TestA does not implement inherited abstract member Run(BaseDataClass)
You can, but the BaseTestClass<SettingsA> base class simply does NOT have a method to override of the signature Run(DataA), but only one of the signature Run(BaseDataClass<DataA>).
The generic inheritance also means that the generic T type is the same.
You can implement this with an additional generic argument, Type-Safe and without cast:
internal abstract class BaseTestClass<T, Y>
where T : class, new()
where Y : BaseDataClass<T>
{
private T m_data;
//base test class implementation
public abstract void Run(Y data);
}
public class BaseDataClass<T> where T : class, new()
{
}
internal class TestA : BaseTestClass<SettingsA, DataA>
{
public override void Run(DataA data)
{
throw new NotImplementedException();
}
}
class DataA : BaseDataClass<SettingsA>
{
}
class SettingsA
{
}
This is type-safe because the constraint is
where Y : BaseDataClass<T>
If you don't need T directly in you base class, you can only use one generic parameter and remove T
Your second method does not compile because there is no method to be overriden by it, removing the override modificator will make your code compile.
If you want to have a method which will run only when the parameter is of type DataA, but still execute the interface method implementation, you can do this way:
class TestA : BaseTestClass<SettingsA>
{
//Works!
public override void Run(BaseDataClass<SettingsA> data)
{
}
public void Run(DataA data)
{
//dp some stuff
Run((BaseDataClass<SettingsA>)data);
}
}
But note that this is not bullet proof, you could miss boxed calls, the better way is do this way:
class TestA : BaseTestClass<SettingsA>
{
//Works!
public override void Run(BaseDataClass<SettingsA> data)
{
var myDataA = data as DataA;
if (myDataA != null)
{
//your parameter is a DataA;
}
}
}
It does not work because you cannot override one method with two methods. Take the override off of one of the methods in TestA, and it will all work. There's no point in overriding a single method twice, anyhow, within a single class.

Conversion of generic types

I have below class structure:
public class FirstContextController : AFirstContextController
public abstract class AFirstContextController : ABaseController<AFirstContextView>
public abstract class ABaseController<TView> where TView : ABaseView
public abstract class AFirstContextView : ABaseContextView
public abstract class ABaseContextView : ABaseView
public abstract class ABaseView : UserControl
Now I create an instance of my controller:
AFirstContextController firstContextController = new FirstContextController();
and need to return it from the method:
public static ABaseController<ABaseContextView> GetContextController( ... )
{
return firstContextController;
}
But then I get an error:
Cannot implicitly convert type 'AFirstContextController' to 'ABaseController'
So I tryied many casting (for example):
return (ABaseController<AFirstContextView>)firstContextController;
return (ABaseController<ABaseContextView>)( (ABaseController<AFirstContextView>)firstContextController );
But still get similar errors according to conversion.
So what conversion should I apply to return it ?
You need an interface derived from ABaseController<ABaseContextView> to make it work.
This has to do with variance and covariance. Reed more about it on MSDN: Covariance and Contravariance in Generics.
You will have to mark the ABaseContextView with out in your interface definition, so the signature should be something like IBaseController<out ABaseContextView>.
Example:
public abstract class ABaseController<TView> : IBaseController<TView> where TView : ABaseView
{
public void SomeMethod() { }
}
And the interface:
public interface IBaseController<out TView> where TView : ABaseView
{
void SomeMethod();
}
Then your current method should read:
public static IBaseController<ABaseContextView> GetContextController( ... )
{
return firstContextController;
}

Categories

Resources