Is it possible to create a generic class<T> which the generic type T will be the base class of it?
i.e:
MyClass<Base1> b1 = new MyClass<Base1>();
MyClass<Base2> b2 = new MyClass<Base2>();
b1.Name="test";
b2.ID=1;
Base Classes:
class Base1
{
protected string Name{ get; set;}
}
class Base2
{
protected int ID{ get; set;}
}
Inherited Class:
class MyClass<T>:T //here is the question is it possible dynamic inheritence
{
}
It's possible to use a constraint on T thus forcing T to be of type baseclass, like this:
public class baseclass
{
// base class code
}
// perfectly valid
public class derived1<T> : baseclass where T : baseclass
{
// derived class code
}
It's impossible to compile the following code, since T is a type parameter, and the compiler must infer it from usage. obviously that can't be done like this.
public class derived2<T> : T
{
// derived class code
}
Related
My base class has a method to serialize itself that I want derived classes to use.
public abstract class Base
{
public int Property1 { get; set; }
public virtual string Serialize()
{
...
return System.Text.Json.JsonSerializer.Serialize(this, jsonSerializerOptions);
}
}
The problem is that "this" in the base classes refers to the base class. When calling Serialize() from derived classes, only the properties of the base class are serialized. What can I use instead of "this" to pass to the Json serializer so that it will refer to the instance of the derived class.
Derived class may look like this:
public class Derived : Base
{
public int Property2 { get; set; }
}
I then call the Serialize() method like this:
Derived derived = new Derived();
string json = derived.Serialize();
Only Property1 is serialized.
The reason of it serialize Property1 only is you didn't override the virtual method in the derived class, So it works only for property1.
Sample:
public abstract class Base
{
public int Property1 { get; set; } = 20;
public virtual void Display()
{
MessageBox.Show(Property1.ToString());
}
}
public class Derived : Base
{
public int Property2 { get; set; } = 9;
public override void Display() //without this you can't achieve what you want
{
base.Display();
MessageBox.Show(Property2.ToString());
}
}
public class Test
{
public void ShowResult()
{
Derived derived = new Derived();
derived.Display();
}
}
Test test = new Test();
{
test.ShowResult();
}
OUTPUT
Two Messageboxes
First displays: 20
Second displays: 9
If I didn't override the virtual method in the derived class the OUTPUT would be:
One Messageboxe ONLY
Displays: 20
From Documentation
When a virtual method is invoked, the run-time type of the object is
checked for an overriding member. The overriding member in the most
derived class is called, which might be the original member, if no
derived class has overridden the member.
we can't change 'this' behavior, but you can try below solution, its work like what you need
class Program
{
static void Main(string[] args)
{
Derived d = new Derived();
Console.WriteLine(d.Serialize());
Console.ReadLine();
}
}
public abstract class Base
{
public int Property1 { get; set; }
}
public class Derived : Base
{
public int Property2 { get; set; }
}
public static class Extensions
{
public static string Serialize(this Base obj)
{
return System.Text.Json.JsonSerializer.Serialize((object)obj);
}
}
The overload method you are using is Serialize< BaseClass >(this, options). This when called from the base class always pass the BaseType as T.
Fortunately, JsonSerializer provides another overload which you can use from baseclass and achieve the desired behavior without overriding in derived class. For this, You should be using Serialize(this,this.GetType(),options). this.GetType() wil always returns the instance type even when call is done from a base class.
This question already has answers here:
Convert List<DerivedClass> to List<BaseClass>
(13 answers)
Closed 5 years ago.
Let's consider that there is an abstract base class and one, or more child classes:
public abstract class BaseInnerClass
{
public int Id { get; set; }
}
public class ConcreteInnerClass : BaseInnerClass
{
public string Name { get; set; }
}
Then, let's assume there is a generic abstract class that has a property of above abstract class type:
public abstract class GeneriAbstractTestClass<T> where T : BaseInnerClass
{
public T InnerClass { get; set; }
}
Then let's make a class that inherits from the class above:
public class ConcreteTestClass : GeneriAbstractTestClass<ConcreteInnerClass>
{
public string ConcreteString { get; set; }
}
So now everything is prepared to ask a question ;) Why it is not possible to do it:
//cannot convert initializer type
GeneriAbstractTestClass<BaseInnerClass> genericClass = new ConcreteTestClass();
while this is allowed:
//ok
BaseInnerClass baseInner = new ConcreteInnerClass();
What's the difference between this two assignments?
This has nothing to do with abstract classes. A simpler example would be
List<BaseInnerClass> base = new List<ConcreteInnerClass>
The fact that type A is derived from type B does not imply that type C<A> is derived from type C<B>. Your example is a little bit more complicated, but it can be explained using the same logic.
Note that you can define another concrete type:
public class EvilConcreteInnerClass : BaseInnerClass
{
}
If what you wanted was possible, then the following would work:
GeneriAbstractTestClass<BaseInnerClass> genericClass = new ConcreteTestClass();
genericClass.InnerClass = new EvilConcreteInnerClass(); // OK, because the compiler sees `T` as `BaseInnerClass`
genericClass variable points to an object whose T generic parameter is ConcreteInnerClass, so assigning EvilConcreteInnerClass to the property would result in a run-time exception.
Actually. You can do this. But you need to specify interface with covariant out T generic, because it is type safe to make those casts.
Example
namespace ConsoleTest
{
class Program
{
static void Main(string[] args)
{
var a = new Generic<Concrete>();
IGeneric<Base> c = new Generic<Base>();
c = a;
}
}
public interface IGeneric<out T> where T: Base
{
T Inner { get; }
}
public class Generic<T> : IGeneric<T>
where T : Base
{
public T Inner { get; set; }
}
public class Concrete : Base
{
}
public class Base
{
}
}
Delegates also not restricted if they specify covariant out generic templates.
It means those casts you want is OK as long as you use readonly generic properties. So, like #Kapol said and provided you example why it is not type safe to allow setters on properties or pass T into function.
Summary
Use ReadOnly interfaces if you want to use those kinds of casts.
Run it here: http://rextester.com/ZMLMB2576
public interface IClass {
int number {get;}
}
public abstract class BaseClass : IClass {
public BaseClass(int n){
number = n+100;
}
public int number { get;set;}
}
public class DerivedClass : BaseClass {
public DerivedClass(int n) : base(n) {
number = n;
}
public int number { get;set;}
}
public class Program
{
public static void Main(string[] args)
{
var foobar = new DerivedClass(1);
Console.WriteLine(GetNumber(foobar)); // 101
}
public static int GetNumber(IClass foo){
return foo.number;
}
}
Why does the function GetNumber not use the most derived class and instead only treats the passed object as BaseClass ?
If it was treating the passed object (foo) as DerivedClass then I suspect the base constructor to run first and then DerivedClass constructor, overriding 101 with 1
Shadowing (number in derived class hides one from base) and the fact that interface is implemented by base class leads to this behavior. Mapping interface methods defined by base class and IClass.number is mapped to BaseClass.number which is completely different from DerivedClass.number.
Fixes:
make property number to be virtual in base class (more standard approach)
derive both classes from the interface so interface actually picks up implementation from derived class (will confuse readers and everyone will try to remove interface from derived thus breaking it again)
class Derived : BaseClass, IClass { ...
Notes:
it is better to explicitly specify new public int number {get;set;} when you shadow members of base class.
C# is not Java and methods/fields are not virtual by default.
Difference between shadowing and overriding in C#?
I've got the following generic abstract class:
public abstract class MyClass<F, T>
where TCurrencyFrom : Book
where TCurrencyTo : Book
{
public int Id { get; set; }
public virtual F First{ get; set; }
public virtual T Second { get; set; }
}
And I got 3 classes which implement this class like:
public class Implementation1 : MyClass<BookType1, BookType2>
{
}
public class Implementation2 : MyClass<BookType2, BookType1>
{
}
Now I got an "EntityTypeConfiguration" for those which looks like:
public class MyClassConfiguration<TMyClass> : EntityTypeConfiguration<TMyClass> where TMyClass: MyClass
{
public MyClassConfiguration()
{
...
}
}
And try to use those like:
public class Implementation1Map : MyClassConfiguration<Implementation1>
{
public Implementation1Map ()
{
...
}
}
But then I get the following error:
Incorrect number of type parameters in reference class MyClass
How can I solve this problem and make sure I have a generic approach on the EntityTypeConfigurations?
Unfortunately this is tricky with .NET generics.
If MyClassConfiguration doesn't actually care about the type arguments, you might want to create a non-generic interface:
public interface IMyClass
{
// Any members of MyClass<,> which don't rely on the type arguments,
// e.g. the Id property
}
Then make MyClass<,> implement IMyClass:
// Type parameters renamed to make the type constraints sensible...
public abstract class MyClass<TCurrencyFrom, TCurrencyTo> : IMyClass
where TCurrencyFrom : Book
where TCurrencyTo : Book
And change the type constraint for MyClassConfiguration:
public class MyClassConfiguration<TMyClass> : EntityTypeConfiguration<TMyClass>
where TMyClass: IMyClass
(Obviously you'll want to give IMyClass a more useful name...)
Alternatively, just make MyClassConfiguration generic in three type parameters:
public class MyClassConfiguration<TMyClass, TCurrencyFrom, TCurrencyTo>
: EntityTypeConfiguration<TMyClass>
where TMyClass: MyClass<TCurrencyFrom, TCurrencyTo>
where TCurrencyFrom : Book
where TCurrencyTo : Book
public class Implementation1Map
: MyClassConfiguration<Implementation1, BookType1, BookType2>
public class Implementation2Map
: MyClassConfiguration<Implementation2, BookType2, BookType1>
It's ugly, but it'll work.
I'm getting a compile error when I try to compile this
The type 'WpfApplication2.CommandInstrumentTrade' cannot be used as type parameter 'T' in the generic type or method 'WpfApplication2.GenericWindowBase'. There is no implicit reference conversion from 'WpfApplication2.CommandInstrumentTrade' to 'WpfApplication2.GenericCommandBase'
public interface IBaseClass
{
int ID { get; set; }
}
public class BaseClass : IBaseClass
{
public int ID { get; set; }
}
public class DerivedClass : BaseClass
{
}
public class Command
{
}
public class GenericCommandBase<T> : Command where T : IBaseClass
{
}
public class DerivedGenericCommand : GenericCommandBase<DerivedClass>
{
}
public class GenericWindowBase<T> where T : GenericCommandBase<IBaseClass>
{
}
public class DerivedGenericWindow : GenericWindowBase<DerivedGenericCommand> // this line fails
{
}
The issue is that Generic<Derived> does not satisfy the condition where T : Generic<Base>. Even if Derived derives from Base, Generic<Derived> does not derive from Generic<Base>
There are many questions like that in StackOverflow.
Try reading those:
C# Generics Inheritance
generic inheritance in C#?
Inheritance doesn't compose with generics. You need to create some kind of converter from one to another. Maybe if you present some less abstract code we could help You