Is it possible to limit the general parameter as a subtype of the current object?

Here is an interesting problem that I just ran into. You can do what I want using extension methods, but it is not possible to do with members of the class itself.

Using extension methods, you can write a method that has a signature that looks like this:

public static void DoStuff<T>(this T arg1, T arg2) 

this ensures that both arguments are of any type that you need. This becomes more useful when used with delegates.

 public static void DoStuff<T>(this T arg1, Action<T> arg2) 

However, I cannot get this to work with members. There is no such limitation as this:

 public void DoStuff<T>(T arg1) where T : typeof(this) 

If this worked, then you can define a method in your base class like this (I used streams as they are built into the hierarchy in .NET):

 class Stream { public void DoStuff<T>(T stream) where T : this { } } 

and then in a subclass it would be impossible to call it this way:

 ByteStream bs = new ByteStream() bs.DoStuff(new Stream()) // Error! DoStuff() should be inferred as DoStuff<ByteStream>() 

Is there any way to do this? I believe it automatically infers types from arguments, and extension methods are syntactic sugar. This is probably why this works; because extension methods are replaced with static calls, which then allow type inference.

I ask because I am trying to move the extension method to a common base class and cannot compile it without adding type information.

To clarify. This is not a case of adding where T : MyType , because if I create a type called MySubType that inherits from MyType , I can call DoStuff on the MySubType instance and pass a MyType as an argument. This also means that in the case when it takes an Action<T> , I will not be able to call MySubType methods without MySubType in the first place.

+4
source share
5 answers

Interestingly, the rules allow you to do this with extension methods, but not with regular instance methods.

Your "typeof (this)" restriction really should be "this.GetType ()". "typeof (this)" makes no sense; typeof accepts a type, not an arbitrary expression.

And as soon as you understand that then the reason why we cannot make such a restriction becomes more clear. Constraints are always checked by the compiler , but it is clear that "this.GetType ()" cannot be determined until runtime. This means that if we had this function, we would introduce a point of failure in the type system at run time:

 abstract class Animal { public void Mate<T>(T t) where T : this { ... CENSORED ... } } ... Animal x1 = new Giraffe(); Mammal x2 = new Tiger(); x1.Mate<Mammal>(x2); 

You cannot pair a tiger with a Giraffe, but where can a compiler find it in a program? Nowhere. The runtime types x1 and x2 are unknown before execution, so violation of restrictions cannot be detected until then.

We hate that. It really sucks to have a program without casting anywhere, which, however, can fail with type system violations, even after a thorough check by the compiler. Array covariance is such a case, and since we support array covariance, we not only sometimes pass the broken program through the compiler, which then crashes, we must slow down each record for each array of the reference type, just to make sure that we are not violating the type system. This is terrible, and we do not want to add more execution points to the type system.

That's why we carefully develop new dispersion functions in C # 4 to ensure that they are always typical. (Except in cases where existing conversion options on arrays are not typical and will still not be typical.) We want to make sure that the compiler can check all restrictions for violation during compilation, instead of spitting new code that Performs check execution times that may end unexpectedly.

+9
source

I think you can do this by simply specifying the type at the end.

 public void DoStuff<T>(T arg1) where T: YourType 

I am doing this currently in a solution, but YourType is an interface. I think you can do it with a specific class.

+3
source

Just use the base class name as a constraint .

 public void DoStuff<T>( T arg1 ) where T : BaseClass 
+1
source

After your clarification, I think the only way to achieve this is to make your base class common. It's a little clumsy, but it should do what you need.

 MySubType foo = new MySubType(); MySubType bar = new MySubType(); foo.DoStuff(bar); // ... public class MySubType : MyBaseType<MySubType> { } public class MyBaseType<T> { public void DoStuff(T arg1) { // do stuff } } 
+1
source

Change it like this:

 public void DoStuff<T>(T arg1) where T : BaseType 

This way you can only use type T, which inherits your BaseType

0
source

All Articles