Convert Derived Class to Base Generic Class - c#

I have a set up approximately like this:
public class A { ... }
public class A<T> : A { ... }
public class B<T> : A<T> { ... }
public class C : B<SomeType> { ... }
I am iterating over a list of type A, and I want to check if something is of type B, and if it is, convert it to... B... I can see how it already poses a problem of how am I gonna get the type... but if I cannot do that, what are my other alternatives?
EDIT:
To clarify, B contains a method I'd like to use that A does not contain as it simply has no need for it... I want to check which of the objects on that list are of type B so that I can run this method on them
EDIT 2:
I forgot to mention the A in the middle earlier... sorry for the confusion

I want to check which of the objects on that list are of type B
Then introduce a type B into your type hierarchy. Currently you don't have a type B, you've got B<SomeType> which is a different type. so
public class A { ... }
public abstract class B : A { ... }
public class B<T> : B { ... }
public class C : B<SomeType> { ... }
Or declare the method you want on an interface
public class A { ... }
public class A<T> : A { ... }
public interface IB
public class B<T> : A<T>, IB { ... }
public class C : B<SomeType> { ... }
Then for any A you can check if it is IB. This is probably the most natural solution since .NET doesn't have multiple inheritance.

Related

Generic interfaces and inheritance to call a generic method

I want to have a generic class which could call a method based on its generic type which is defined by a derived class. For that I implemented a base interface and a generic interface which has the base interface as generic and also derives from the base interface.
In the generic interface I want a method based on the type T of the base interface.
After that I wanted to implement a class based on the generic interface which should be able to call the generic method. This is the example code:
public interface BaseInterface
{ }
public interface GenericInterface<T> : BaseInterface where T : BaseInterface
{
void Foo(T t);
}
public class C<T> : GenericInterface<T> where T : BaseInterface
{
public C()
{
// None of these works
Foo(this);
Foo((T)this);
Foo((BaseInterface)this);
}
public void Foo(T t) { }
}
Is there a way to achieve my desired behavior here?
The error message here is:
cannot convert from 'C<T>' to 'T'
which in my eyes should be possible because C derives from BaseInterface which is T
While both C<T> and T need to derive from BaseInterface, that does not mean that then need to be the same. I might for example declare another type B : BaseInterface, and C<B>. So we would get the method Foo(B t) , it would obviously not be possible to call the method with this as the parameter, since C<B> is not B.
If you just need a method that needs a BaseInterface parameter, just declare it as Foo(BaseInterface t) instead. That way you could call it with this without any problem.
It looks like you're looking for something like the Curiously Recurring Template Pattern for C#. In a simplified form it looks like this:
class Base<T>
{
public void Foo(T t) { }
}
class C : Base<C>
{
C()
{
Foo(this);
}
}
In your case T is a type that derives from BaseInterface. Although C<T> also derives from BaseInterface it doesn't mean that you can bind a C<T> to T t. It's like trying to bind a string to a List, just because both implement IEnumerable. They are still different types.
For your full example it could look like this
public interface BaseInterface
{ }
public interface GenericInterface<T> : BaseInterface where T : BaseInterface
{
void Foo(T t);
}
public class C<T> : GenericInterface<C<T>> where T : BaseInterface
{
public C()
{
Foo(this);
}
public void Foo(C<T> t) { }
}
Here's what you need for the Curiously Recurring Template in C#.
public interface BaseInterface { }
public interface GenericInterface<T> : BaseInterface where T : GenericInterface<T>
{
void Foo(T t);
}
public abstract class C<T> : GenericInterface<T> where T : C<T>
{
public abstract void Foo(T t);
}
Now you can go ahead and implement a real class:
public class D : C<D>
{
public D()
{
Foo(this);
Foo((D)this);
}
public override void Foo(D t) { }
}
That works fine.
However, calling Foo((BaseInterface)this); will never work in this code. It just doesn't make sense.
I Tried this, maybe can help you
public class C<T> : GenericInterface<T> where T : BaseInterface
{
public C()
{
T t = default(T);
BaseInterface bi;
bi = t; // here can cast , bacuse T : BaseInterface , not BaseInterface : T
t = bi;//here cast error ,
}
public void Foo(T t) { }
}
It's same like this case:
public class B { }
public class A : B
{
public void CastTest()
{
A a = null;
B b = null;
b = a;
a = b;//here error
}
}

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
}

C# Generics - Classes implementing other generic classes

I have a
public class A<T> where T : IBase
{
//Does something
}
I need a second class that behaves like a collection of class A
public class B<A<T>> : IEnumerable<A<T>> where T : IBase
{
}
The problem is that I do not want to create classes like
public class B<A<MyCustomObjectP>> : IEnumerable<A<MyCustomObjectP>>
{
}
public class C<A<MyCustomObjectQ>> : IEnumerable<A<MyCustomObjectQ>>
{
}
and so on.. I would like to let the CustomObject be a generic type parameter that implements IBase.
I found that even doing this is illegal:
public class B<T, U> : IEnumerable<T> where T : A<U> where U : IBase
{
}
How could I achieve this type of behaviour, if this is illegal? Is there a better design pattern of sorts that might help?
The IBase constraint is defined on A<T>, so it must be defined again on all generic classes, that want to use A<U> (using U to distinguish from T in A<T> class definition, but it can be called anything). You should be able to do simply:
public class B<T> : IEnumerable<A<T>> where T : IBase { ... }
You wrote that you need a second class that behaves like a collection of class A.
Since you have other classes (like B) inheriting from IBase as well, which you want to add, you can make the collection a collection of IBase.
Hence the solution would look like this (note that I have used List but you can easily replace that by IEnumerable - but then you have to implement methods like .Add yourself):
void Main()
{
var items = new CollectionOf<IBase>(); // create list of IBase elements
items.Add(new A() { myProperty = "Hello" }); // create object of A and add it to list
items.Add(new B() { myProperty = "World" }); // create object of B and add it to list
foreach(var item in items)
{
Console.WriteLine(item.myProperty);
}
}
// this is the collection class you asked for
public class CollectionOf<U>: List<U>
where U: IBase
{
// collection class enumerating A
// note you could have used IEnumerable instead of List
}
public class A: IBase
{
// class A that implements IBase
public string myProperty { get; set; }
}
public class B: IBase
{
// class B that implements IBase too
public string myProperty { get; set; }
}
public interface IBase {
// some inteface
string myProperty { get; set; }
}

Inhertiance using generic type constraint

How can I properly inherit a class (of another class and interfaces) that have a generic type with a generic type constraint (where)?
class A { }
class B { }
interface I { }
class C<T> where T : A, B, I { }
In this example A, B and I is treated as base for T. Inhertiance of 2 classes is not possible in C#.
But I want that A is Baseclass of the generic type T and B/I is baseclass/interface of C. How to do this?
As soon as I use the where-constraint for the generic type I cannot derive my class C anymore
public class A
{
}
public class B
{
}
public interface I
{
}
public class C<T> : B, I where T : A
{
}

Covariance issue

I'm facing a bit of problem with the following casting:
class A
{
}
class B : A
{
}
class C<T> where T : A
{
protected T property { get; set; }
}
class D : C<B>
{
}
class MainClass
{
public static void Main (string[] args)
{
C<A> x = new D();
// Error CS0029: Cannot implicitly convert type `SampleApp.D' to `SampleApp.C<SampleApp.A>' (CS0029) (SampleApp)
}
}
I don't understand why this is failing since D is wider than C<A> since it implements C<B>, and B : A. Any workarounds?
If you can use C# 4.0, you can write the following code.
class A { }
class B : A {}
interface IC<out T> {}
class C<T> :IC<T> where T : A { protected T property { get; set; } }
class D : C<B> {}
class MainClass {
public static void Main()
{
IC<A> x = new D();
}
}
Let's name your classes Animal for A, Barker for B, and Dog for D.
Actually C<Animal> is wider than Dog : C<Barker>. Assume you have public property Me of type T and assignment possible:
C<Animal> a = new Dog();
a.Me = Elephant; // where Elephant inherited from Animal
Oops! Dog is parametrized with Barker. Have you seen barking elephants?
You need to declare some covariant interface to allow assignment of class instantiated with more derived type argument C<Barker> to object instantiated with less derived type argument C<Animal>. You can use empty interface, like #NickW suggested, but you will not be able to do something with instance of that interface (it's empty!). So, let's do something like that:
interface IC<out T>
where T : Animal
{
IEnumerable<T> Parents(); // IEnumerable is covariant
T Me { get; } // no setter
}
class C<T> : IC<T>
where T: Animal
{
// implementation
}
class D : C<Barker>
{
// implementation
}
Above scenario is still impossible, but now you can
IC<Animal> a = new Dog();
foreach(var parent in a.Parents)
Console.WriteLine(parent);
Console.WriteLine(a.Me);
You can't do that because the Generics are actualy templates and they don't act like what you want to do with them. Let me show you by this:
When you say "C<A>" it means a generic class by a "parameter" of "A".
BUT
When you say "D" it means exactly "D"!
So D is not equal to a generic class by a parameter of A. As you can simply see it in the result of ToString function on both types (by using typeof).
Hope it helps
Cheers

Categories

Resources