Cannot use polymorphism because of generic base class - c#

I create base generic class with no fields with just one method
public class Base<T> where T:class
{
public static T Create()
{
// create T somehow
}
}
public class Derived1 : Base<Derived1>
{
}
public class Derived2 : Base<Derived2>
{
}
public class Program
{
bool SomeFunction()
{
// Here I need reference to base class
Base baseref; // error here
switch(somecondition)
{
case 1:
baseref = Derived1.Create();
break;
case 2:
baseref = Derived1.Create();
break
}
// pass baseref somewhere
}
}
An obvious option would be converting base class to interface, but this is not possible because interface cannot contain static methods.
I think I need some intermediate base class. Please suggest

You must remove the generic parameter from the Base class, you can move it to just the Create method:
public class Base
{
public static T Create<T>() where T : class
{
return Activator.CreateInstance<T>();
}
}
public class Derived1 : Base
{
}
public class Derived2 : Base
{
}

Preliminary Assessment
With this statement,
public class Derived1 : Base<Derived1> {
you're using Derived1 in two different ways according to the base class.
You're effectively telling the C# compiler that Derived1 both:
inherits Base
and Base uses instances of Derived1 through non-inheritance means.
This is not wrong (if that's what you really want), but it's unusual for most programming scenarios; you normally choose one or the other. However the benefit of your logic is: not only do you have an implicit instance of Derived1 through inheritance (same for any other derived class), but the base class can also handle other external instances of that same derived type through the type parameter <T>
One problem I see in the Base class is it turns into a kind of circular scenario when using the factory method as intended, because, to support all derived classes it would need to support something like class Base<T> where T:Base<T>. That's next to impossible to declare because you would have to say in a circular fashion: Base<Base<Base<!!!>>> baseref = null; where !!! represents an infinite number of the same.
One Solution...
One possible (and strong solution) is to move the Type parameter from the class to the factory Create method and restrict its usage to the Base class type like so:
using System;
public abstract class Base
{
public static T Create<T>() where T : Base
{
return Activator.CreateInstance<T>();
}
}
Note: I have made the base class abstract which restricts instantiation to the derived types; however you can still use base class references (see switch statement usage below).
These derived classes still inherit from base.
public class Derived1 : Base
{
}
public class Derived2 : Base
{
}
Your factory method is restricted to create only instances of derived types. The logic has been swapped around so the derived type is given to the factory method instead of the factory method being called on it.
public class Program
{
bool SomeFunction()
{
Base baseref = null;
switch(DateTime.Now.Second)
{
case 1:
baseref = Base.Create<Derived1>(); // OK
break;
case 2:
baseref = Base.Create<Derived2>(); //OK
break;
case 60:
baseref = Base.Create<string>(); //COMPILE ERR - good because string is not a derived class
break;
}
// pass baseref somewhere
}
}

public abstract class Base
{
}
public class Base<T> : Base where T : class
{
public static T Create()
{
// create T somehow
}
}
public class Derived1 : Base<Derived1> // also inherits non-generic Base type
{
}
public class Derived2 : Base<Derived2> // also inherits non-generic Base type
{
}

How about creating an interface and having the abstract class implement the interface?

Related

Do I need to define a same Interface in a derived class after define it in a base class? [duplicate]

This question already has answers here:
Can a child class implement the same interface as its parent?
(5 answers)
Closed 3 years ago.
For example,I have a base class like this:
class Base: ICloneable
{
public object Clone()
{
//something
}
}
And is there any difference between these Derived classes?
class Derived: Base, ICloneable
{
//something
}
class Derived: Base
{
//something
}
Well, you may need to do it; here is a possible scenario:
When cloning, we usually want to return not universal object by cloned object type:
class Base {
// We can't declare this method as virtual: Derived class will return Derived
public Base Clone() {
...
}
}
...
Base test = new Base();
Base duplicate = test.Clone();
If we want to implement IClonable we have to do it explictly (in order to solve Clone() names conflict):
class Base : ICloneable {
public Base Clone() {
...
}
// This method is efficiently private, and that's why can't be virtual
object ICloneable.Clone() => Clone();
}
Now we want a Derived class which can be cloned as well:
class Derived : Base {
// Note that now we have new Clone method which returns Derived instance (not Base one)
public new Derived Clone() {
...
}
}
...
Derived test = new Derived();
Derived duplicate = test.Clone();
If we keep it like this then we'll have wrong behaviour:
Derived test = new Derived();
// This will be wrong:
// Base.ICloneable.Clone() will be called which executes "Base Clone()" method
// instead of expected "new Derived Clone()"
object clone = (test as IClonable).Clone();
So we have to reimplement IClonable interface:
class Derived : Base, ICloneable {
// Please, note that now we have new Clone method which returns Derived instance
public new Derived Clone() {
...
}
// This ICloneable implementation will call Derived Clone()
object ICloneable.Clone() => Clone();
}
...
// Derived ICloneable.Clone() will be called
// which executes "new Derived Clone()" method
object clone = (test as IClonable).Clone();
Actually, you can do this, if your derived class provides its own (explicit) implementation of the interface:
class B : A, Icloneable
{
object IClonable.Clone()
{
// do something completely new
}
}
As this is an explicit implementation, you have to cast your B-instance to the interface in order to call the new implementation. Otherwise the implementation from A is used (see my fiddle: https://dotnetfiddle.net/tuUnCm).
No, you do not have to implement the interface in the derived class. The derived class can also be cast as the interface type when the base class implements the interface. Like this:
public interface ISomething
{
void Say();
}
public abstract class BaseClass : ISomething
{
public void Say(string something)
{
Console.WriteLine("Say: " + something);
}
}
public class DerivedClass : BaseClass
{
}
var x = new DerivedClass() as ISomething;
x.Say("Derived");
If understanding the problem correctly, you don't need to inherit for base and ICloneable as base already inherits from it.
This is fine
class base:ICloneable
{
public object Clone()
{
//something
}
}
This is fine too, as derived1 will inherit ICloneable, as its part of your base class
class derived1:base
{
//something
}
However this is saying it will, inherit from base (which already inherits from ICloneable) AND ICloneable. Its redundant and defeats the purpose of having an interface.
class derived1:base,Icloneable
{
//something
}
Hope that helps!
No need, when your base class is implementing interface or other classes all the properties and functionality introduced in base class will inherit to derived class.

Base interface in c#

I need some sort of way to mark base interfaces and identify if a class implemented the base interface or its derived interface. c# doesn't allow having 'abstract interface'. Is there any way to do this in c#?
public interface IBaseFoo
{
void BaseMethod();
}
public interface IFoo : IBaseFoo
{
void FooMethod();
}
public class Base
{
}
public class A : Base, IFoo
{
}
public class B : Base, IBaseFoo
{
}
Now in the following method I need to check if the typeCls is implemented the IFoo or IBaseFoo without explicitly specifying types. I need sort of a way to mark the base interface and identify it in the method. (ie: if c# allowed having abstract interface, I could have check if IsAbstract property of interfaces of typeClas)
public bool IsBaseFooImplemented<T>(T typeCls) where T : Base
{
// Here I need to check if the typeCls is implemented the IFoo or IBaseFoo
}
Because IFoo : IBaseFoo, every class implementing IFoo also implements IBaseFoo. But not the other way around, so you can simply check whether typeCls is IFoo.
Do note that changing behavior based on implemented interfaces generally is a design smell that bypasses the use for interfaces in the first place.
//somewhere define
static List<IBaseFoo> list = new List<IBaseFoo>();
public class A : Base, IFoo
{
public A()
{
YourClass.list.add(this);
}
}
public class B : Base, IBaseFoo
{
public B()
{
YourClass.list.add(this);
}
}
//then you can check if a class is IFoo or not.
public bool IsBaseFooImplemented<T>(T typeCls) where T : Base
{
foreach(var c in list )
{
if(typeof(c) == typeCls) return true;
}
return false;
}
I have not tested the code but it should work.

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.

Returning child type in Parent class

public abstract class Base
{
public Base ClassReturn()
{
return this;
}
}
Is there possibility to return child type that invoked ClassReturn method?
I've done that in extension method:
public static T ClassReturn<T>(this T obj) where T : Base
{
return (T) obj.ClassReturn();
}
But I want to embeed it in Base class instead of extension method. Is there possibility to do that with generics?
I will copy my comment which describes what I want to achieve:
I need something similiar to builder pattern and I have different
classes that depending on previous operations do something else, now I
want to have a similiar functionality in every of them and when I use
it I lose object type. So my solution is either implement that
functionality multiple times in every class or create extension
method. But I always thought when it is possible to make extension
method for class then I can embeed that in class, but as I see it is
not possible.
Full example:
public class Child1 : Base
{
public Child1 Operation1()
{
Console.WriteLine("operation1");
return this;
}
}
public class Child2 : Base
{
public Child2 Operation2()
{
Console.WriteLine("operation2");
return this;
}
}
static void Main(string[] args)
{
Child1 ch = new Child1();
ch.Operation1().Operation1().ClassReturn().Operation1()
}
I can't use Operation1 after ClassReturn if I don't use extension method.
Try this one:
public abstract class Base<T> where T: Base<T>
{
public T ClassReturn
{
get { return (T)this; }
}
}
public class Child1 : Base<Child1>
{
}
public class Child2 : Base<Child2>
{
}
From your question and your comments, what you are trying to achieve is not possible directly from the type system. By returning an instance of Base you are specifically saying that all you are interested is that you have something that derives from Base, but that the specific class doesn't matter. Statically, the compiler no longer has the information it needs to perform a cast.
If you are trying to get the original type back statically, then you have to supply the information to the compiler, and in this case you can't guarantee that you have the correct information. In the example below, the instance is created from derived type A but attempted to be cast to derived type B through the extension, the compiler will allow the code to compile, but you'll get an exception at runtime.
public class A : Base { }
public class B : Base { }
public static class BaseExtensions
{
public static T GetAsT<T>(this Base base) where T: Base
{
return (T)base;
}
}
public static void Main()
{
Base obj = new A();
B b = obj.BaseAsT<B>(); // This compiles but causes an exception
}
You should look up the Liscov Substitution Principle to get information on how to properly work with base and derived classes in the system as a whole, and then write up a question dealing specifically with the result you are trying to achieve.

C#: Override generic method using class generic parameter

Why is this not possible?
abstract class A
{
public abstract T f<T>();
}
class B<T> : A
{
public override T f()
{
return default (T);
}
}
Errors:
does not implement inherited abstract member 'A.f<T>()'
no suitable method found to override
I know that the signature must be same, but from my point of view I see no reason what could possibly be wrong that this is forbidden.
Also I know that another solution is to make A generic, rather than its method, but it is not suitable for me for some reason.
This is not possible because those methods have different signatures. A.f is generic method and B.f is not (it merely uses class generic argument).
You can see this form caller perspective:
A variableA = new A();
variableA.f<int>();
B<int> variableB = new B<int>();
variableB.f();
B does not fulfil the contract of A.
A allows f to be called with any type parameter to return that type. B doesn't allow f to be called with a type parameter, and just returns the type of B's type parameter.
For example, say you had a B<int> and cast it to an A (which should be possible as it inherits from it). Then you called f<bool>() on it (which should be possible as it's an A). What then? The underlying B<int> doesn't have a method to call.
B b = new B<int>();
// This is legal as B inherits from A
A a = b;
// This is a legal call, but how does b handle it?
bool result = a.f<bool>();
In the case of your code
abstract class A
{
public abstract T f<T>();
}
class B<T> : A
{
public override T f()
{
return default (T);
}
}
what do you expect to be called in the below code
public void Foo(A myObj) {
myObj.f<DateTime>();
}
Foo(new B<int>());
There's no implementation for that method though the type contract (the abstract class A) clearly states that you need an implementation. So you can either implement or change the contract to use a type argument at the class level
abstract class A<T>
{
public abstract T f();
}
class B<T> : A<T>
{
public override T f()
{
return default (T);
}
}
does compile however it also limits f of course
Probably this is what you intend to do:
abstract class A
{
public abstract T f<T>();
}
class B<U> : A
{
public override T f<T>() //also needs to have a generic type parameter
{
throw new NotImplementedException();
}
public U f()
{
return f<U>();
}
}
The generic method type parameter and the generic class type parameter (here T and U) have no straightforward connection, i.e. T is not restricted to be U (or something) in the base class and you cannot change this restriction in the derived class.
abstract class A
{
public abstract T f<T>();
}
class B<T> : A
{
public override T f<T>()
{
return default (T);
}
}

Categories

Resources