Enforcing generic interface childs type - c#

I have a generic interface (MyInterface<T>), which is implemented by the class ChildA in the example below:
public interface MyInterface<T>
{
MyObj<T> GetObj(); // Irrelevant
}
class ChildA : MyInterface<ChildA>
{
// Irrelevant:
MyObj<ChildA> GetObj() {
return new MyObj<ChildA>();
}
}
This works, but I need to make sure that <T> always has the type of the implementing class, so in this case T should always be of type ChildA, because it is implemented by ChildA.
Another correct implementation could be this, for example:
class ChildB : MyInterface<ChildB> { ... }
But currently, this incorrect implementation is also possible, while it should not be:
class ChildA : MyInterface<ChildB> { ... }
Is there a way to enforce this?

You cannot enforce a generic type argument to be constrained to the implementing type.
The available type constraints are the following:
where T : struct
where T : class
where T : new()
where T : <base class name>
where T : <interface name>
where T : U
There is nothing like where T : self in C#. Actually, it wouldn't even make sense, because such a thing cannot be meaningfully enforced. Besides, it wouldn't fit at all into the covariance/contravariance concepts and would be weird to inherit from, in general.
The closest thing you can do is this:
public interface IMyInterface<T> where T : IMyInterface<T>
{
MyObj<T> GetObj();
}
Why it wouldn't make sense
Let's say you could do this:
public interface IMyInterface<T> where T : self // this syntax does not exist in C#
{
MyObj<T> GetObj();
}
Now all implementing types would have to use themselves as the type argument. But you could still do this:
public class ChildC<T> : IMyInterface<T> where T : self
{
/* ... */
}
Which would go around your restriction.

Is there a way to enforce this?
Well, not with generic constraints. You can do that with reflection though i'd vote against it :
public abstract class BaseChild<T> : MyInterface<T>
{
protected BaseChild()
{
if (typeof(T) != this.GetType())
{
throw new InvalidOperationException(string.Format(
"Type {0} is not supported as valid type parameter for type {1}",
typeof(T).Name, this.GetType().Name));
}
}
}
Example :
class ChildA : BaseChild<int> { }
// Bang! throws
var instance = new ChildA();
.
class ChildB : BaseChild<ChildB> { }
// Ok here
var instance = new ChildB();

You cannot do this but you can create your own control comparing the generic type of the interface and the type of your class. See the example:
class ChildA : MyInterface<ChildB>
{
public ChildA()
{
this.ValidateGenericType();
}
public MyObj<ChildB> GetObj()
{
return new MyObj<ChildB>();
}
protected void ValidateGenericType()
{
//throws an Exception because ChildB is different of ChilA
if (this.GetType().Name != this.GetType().GetInterfaces()[0].GetGenericArguments()[0].Name)
{
throw new Exception("The generic type must be of type ChildA.");
}
}
}

It seems that you should use extension methods instead of enforcing some interface for this purpose
public interface ISomeInterface {}
public class Child: ISomeInterface {}
public class OtherChild : ISomeInterface { }
public static class MyInterfaceExtensions
{
public static MyObj<T> GetMyObj<T>(this T child) where T : ISomeInterface
{
return new MyObj<T>();
}
}
public static class Test
{
public static void RunTest()
{
var child = new Child();
var otherChild = new OtherChild();
MyObj<Child> myObj = child.GetMyObj();
MyObj<OtherChild> myOtherObj = otherChild.GetMyObj();
}
}

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
}

Return a subclass of abstract return type?

My project is structured the following way:
// Abstract class
public abstract class Job
{
public abstract JobResult Run();
}
public abstract class JobResult { }
// Concrete implementer
public class Job1 : Job
{
public override Job1Result Run() { }
}
public class Job1Result : JobResult { }
Each concrete job inherits from Job and implements the method Run which returns a concrete class of JobResult.
However when I do this I get the compiler error:
Job1.Run()': return type must be JobResult to match overridden member
Job.Run()
Is it really not possible to return an inheriting object of the return type when overriding an abstract method?
This is the whole concept of inheritance. Returning parent classes is considered a feature here. Nothing stops you however from returning a Job1Result in Job1
public JobResult Run()
{
return new Job1Result();
}
Then the caller of Job1.Run() will have to know the correct return type and cast it to access Job1Result methods which are specific to that class
You could make Job generic:
public abstract class Job<TResult> where TResult : JobResult
{
public abstract TResult Run();
}
public class Job1 : Job<Job1Result>
{
public override Job1Result Run()
{
//
}
}
Here is an example, I hope it can help you.
public interface IEvent
{
Type GetEventType();
}
public abstract class AEvent<A>: IEvent where A: struct
{
public Type GetEventType()
{
return typeof (A); // return sub struct type
}
}

Casting generic parameter to subclass

Please look at the code bellow:
public class BaseClass
{
}
public class SubClass : BaseClass
{
}
public class QueryClass
{
public TBaseClass[] QueryBase<TBaseClass>() where TBaseClass : BaseClass
{
throw new NotImplementedException();
}
public TSubClass[] QuerySub<TSubClass>() where TSubClass : SubClass
{
throw new NotImplementedException();
}
public TClass[] Query<TClass>() where TClass : BaseClass
{
if (typeof(TClass).IsSubclassOf(typeof(SubClass)))
{
return QuerySub<TClass>(); // there is error The type 'TClass' must be convertible to SubClass
}
return QueryBase<TClass>();
}
}
The question is how to implement Query method. If it is possible..
What you are trying to do is doing something like this:
public class Animal { }
public class Dog : Animal { }
public void HandleAnimal<T>() where T : Animal
{
}
public void HandleDog<T>() where T : Dog
{
}
When you have a reference to Animal in this case, there is no way of knowing what typeof animal it is. Even if the method returns true, in the context of your code it is still always an Animal and you can't handle a dog when all you know is that the type is an animal. If you were handling instances of objects inside the method you could potentially start casting or instansiating the subclass if you know that it is a subclass and then pass that through.
Ended up with reflection.
if (typeof(TClass).IsSubclassOf(typeof(SubClass)))
{
var method = typeof(QueryClass).GetMethod("QuerySub").MakeGenericMethod(typeof (TClass));
return (TClass[]) method.Invoke(this, new object[0]);
}

Generic class with self-referencing type constraint

Consider the following code:
abstract class Foo<T>
where T : Foo<T>, new()
{
void Test()
{
if(Bar != null)
Bar(this);
}
public event Bar<T> Bar;
}
delegate void Bar<T>(T foo)
where T : Foo<T>, new();
The line Bar(this) results in the following compiler Error:
Argument type Foo<T> is not assignable to parameter type T
T is constrained to Foo<T> as I want derived classes to basically tell the base class their type, so that the type can be used in the event callback in order to save the implementor from having to cast the callback argument to the derived type.
I can see the code doesn't quite work but I'm having a bit of a blockage as to how to do this correctly without ending up with a generic delegate that can be used for any old thing. I'm also not quite sure why the T constraint doesn't create a compiler error considering it seems to be recursive.
EDIT
I need to clarify this I think! Here's a new example which, I hope will be much clearer. Note below that the OnDuckReady event handler below generates a compiler error.
How do I get the event to pass in the correct type?
abstract class Animal<T>
where T : Animal<T>, new()
{
void Test()
{
if(AnimalReady != null)
AnimalReady(this);
}
public event AnimalHandler<T> AnimalReady;
}
delegate void AnimalHandler<T>(Animal<T> animal)
where T : Animal<T>, new();
class Duck : Animal<Duck>
{
public void FlyAway()
{
}
}
class Test
{
void Main()
{
Duck duck = new Duck();
duck.AnimalReady += OnDuckReady; // COMPILER ERROR
}
void OnDuckReady(Duck duck)
{
duck.FlyAway();
}
}
You can cast 'this' to T:
Bar((T)this);
This however will fail if you have the following:
public class MyFoo : Foo<MyFoo> { }
public class MyOtherFoo : Foo<MyFoo> { }
Because 'MyOtherFoo' is not an instance of 'MyFoo'. Take a look at this post by Eric Lippert, one of the designers of C#.
The code would be clearer if you didn't use "Bar" for two purposes. That having been said, I think what's needed is to use a generic with two parameters (e.g. T and U) such that T derives from U, and U derives from Foo. Alternatively, it's possible to do some nice things with interfaces. A useful pattern is to define:
interface ISelf<out T> {T Self<T> {get;}}
and then, for various interfaces that one might want to combine in an object:
interface IThis<out T> : IThis, ISelf<T> {}
interface IThat<out T> : IThat, ISelf<T> {}
interface ITheOtherThing<out T> : ITheOtherThing, ISelf<T> {}
If classes that implement IThis, IThat, and ITheOtherThing also implement ISelf<theirOwnTypes>, one can then have a routine whose parameter (e.g. "foo") has to implement both IThis and IThat accept the parameter as type IThis. Parameter "foo" will be of type IThis (which in turn implements IThis) while Foo.Self will be of type IThat. Note that if things are implemented this way, one may freely typecast variables to any desired combination of interfaces. For example, in the above example, if the object passed as "foo" was a type which implemented IThis, IThat, ITheOtherThing, and ISelf<itsOwnType> it could be typecast to ITheOtherThing>, or IThis, or any other desired combination and arrangement of those interfaces.
Really a pretty versatile trick.
Edit/Addendum
Here's a somewhat more complete example.
namespace ISelfTester
{
interface ISelf<out T> {T Self {get;} }
interface IThis { void doThis(); }
interface IThat { void doThat(); }
interface IOther { void doOther(); }
interface IThis<out T> : IThis, ISelf<T> {}
interface IThat<out T> : IThat, ISelf<T> {}
interface IOther<out T> : IOther, ISelf<T> {}
class ThisOrThat : IThis<ThisOrThat>, IThat<ThisOrThat>
{
public ThisOrThat Self { get { return this; } }
public void doThis() { Console.WriteLine("{0}.doThis", this.GetType()); }
public void doThat() { Console.WriteLine("{0}.doThat", this.GetType()); }
}
class ThisOrOther : IThis<ThisOrOther>, IOther<ThisOrOther>
{
public ThisOrOther Self { get { return this; } }
public void doThis() { Console.WriteLine("{0}.doThis", this.GetType()); }
public void doOther() { Console.WriteLine("{0}.doOther", this.GetType()); }
}
class ThatOrOther : IThat<ThatOrOther>, IOther<ThatOrOther>
{
public ThatOrOther Self { get { return this; } }
public void doThat() { Console.WriteLine("{0}.doThat", this.GetType()); }
public void doOther() { Console.WriteLine("{0}.doOther", this.GetType()); }
}
class ThisThatOrOther : IThis<ThisThatOrOther>,IThat<ThisThatOrOther>, IOther<ThisThatOrOther>
{
public ThisThatOrOther Self { get { return this; } }
public void doThis() { Console.WriteLine("{0}.doThis", this.GetType()); }
public void doThat() { Console.WriteLine("{0}.doThat", this.GetType()); }
public void doOther() { Console.WriteLine("{0}.doOther", this.GetType()); }
}
static class ISelfTest
{
static void TestThisOrThat(IThis<IThat> param)
{
param.doThis();
param.Self.doThat();
}
static void TestThisOrOther(IThis<IOther> param)
{
param.doThis();
param.Self.doOther();
}
static void TestThatOrOther(IThat<IOther> param)
{
param.doThat();
param.Self.doOther();
}
public static void test()
{
IThis<IThat> ThisOrThat1 = new ThisOrThat();
IThat<IThis> ThisOrThat2 = new ThisOrThat();
IThis<IOther> ThisOrOther1 = new ThisOrOther();
IOther<IThat> OtherOrThat1 = new ThatOrOther();
IThis<IThat<IOther>> ThisThatOrOther1 = new ThisThatOrOther();
IOther<IThat<IThis>> ThisThatOrOther2a = new ThisThatOrOther();
var ThisThatOrOther2b = (IOther<IThis<IThat>>)ThisThatOrOther1;
TestThisOrThat(ThisOrThat1);
TestThisOrThat((IThis<IThat>)ThisOrThat2);
TestThisOrThat((IThis<IThat>)ThisThatOrOther1);
TestThisOrOther(ThisOrOther1);
TestThisOrOther((IThis<IOther>)ThisThatOrOther1);
TestThatOrOther((IThat<IOther>)OtherOrThat1);
TestThatOrOther((IThat<IOther>)ThisThatOrOther1);
}
}
}
The thing to note is that some classes implement different combinations of IThis, IThat, and IOther, and some methods require different combinations. The four non-static classes given above are all unrelated, as are the interfaces IThis, IThat, and IOther. Nonetheless, it is possible for method parameters to require any combination of the interfaces provided that implementing classes follow the indicated pattern. Storage locations of a "combined" interface type may only be passed to parameters which specify the included interfaces in the same order. An instance of any type which properly implements the pattern, however, may be typecast to any "combined" interface type using any subset of its interfaces in any order (with or without duplicates). When used with instances of classes that properly implement the pattern, the typecasts will always succeed at run-time (they could fail with rogue implementations).
delegate void Bar<T>(Foo<T> foo) where T : Foo<T>, new();
It works great. I tested it.
here is the test code
public abstract class Foo<T> where T :Foo<T> {
public event Bar<T> Bar;
public void Test ()
{
if (Bar != null)
{
Bar (this);
}
}
}
public class FooWorld : Foo<FooWorld> {
}
public delegate void Bar<T>(Foo<T> foo) where T : Foo<T>;
class MainClass
{
public static void Main (string[] args)
{
FooWorld fw = new FooWorld ();
fw.Bar += delegate(Foo<FooWorld> foo) {
Console.WriteLine ("Bar response to {0}", foo);
};
fw.Test ();
}
}

Categories

Resources