Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to make "this type" for generics in C#?

Tags:

c#

.net

generics

Kind of theoretical question. Quite long so feel free to skip if you are not in the mood for theory.

Imagine that you have two classes, one inherited from another. The base class is generic and has a method that in the closed type must return some instance of this closed type.

Like this (note ??? in text):

public class Adapter<T>
{
 public virtual ??? DoSomething()
 {
  ...
 }
}

public class AdaptedString : Adapter<String>
{
 public override AdaptedString DoSomething()
 {
  ...
 }
}

I can't do it because there is no way to refer to a closed type that will be derived from a generic type. (Sorry for broken language, just don't know how to express it.) There is no keyword to set in place of ??? to specify that this method will return instance of type that would be derived from this generic type.

Instead, I can use a workaround of explicitly passing the type name to the generic base. But it looks redundant.

public class Adapter<TThis,T>
{
 public virtual TThis DoSomething()
 {
  ...
 }
}

public class AdaptedString : Adapter<AdaptedString,String>
{
 public override AdaptedString DoSomething()
 {
  ...
 }
}

And if in the base class I need to access members of TThis instance, I have to add a constraint. This time it looks ugly - note the constraint:

public class Adapter<TThis,T>
 where TThis : Adapter<TThis, T>
{
 protected int _field; 

 ...

 public bool Compare( TThis obj )
 {
  return _field == obj._field;
 }
}

public class AdaptedString : Adapter<AdaptedString,String>
{
 ...
}

Yes, it is all working, but it would look better if I can simply use some keyword instead of ??? in first code fragment. Something like "thistype".

How do you think will it work? Is it useful? Or maybe this is just plain stupid?

like image 783
XOR Avatar asked Sep 09 '09 16:09

XOR


People also ask

How do you make a generic type?

Remarks. The MakeGenericType method allows you to write code that assigns specific types to the type parameters of a generic type definition, thus creating a Type object that represents a particular constructed type. You can use this Type object to create run-time instances of the constructed type.

Is it possible to inherit from a generic type?

You can't inherit from a Generic type argument. C# is strictly typed language. All types and inheritance hierarchy must be known at compile time. . Net generics are way different from C++ templates.

What are Constrant with type parameters in generic?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.


2 Answers

There's nothing which makes this pattern easier, and in fact the pattern isn't quite bulletproof anyway - because you can have:

class TypeA : Adapter<TypeA, string>

class TypeB : Adapter<TypeA, string> // Bug!

The second line here is entirely legal - TypeA is a valid type argument for the TThis type parameter, even though it's not what we wanted. Basically the type system doesn't let us express the concept of "T must be this type."

I disagree with those who say it's a bad or useless pattern, however. I've found it useful (if complicated) in Protocol Buffers - which would be much worse off without it. For example:

Foo foo = new Foo.Builder { Name="Jon" }.Build();

wouldn't work if Foo.Build() wasn't strongly typed to return Foo, even though the Build method is specified in IBuilder<...>.

It's worth avoiding this if you easily can simply because it gets so complicated - but I do think it's a useful pattern to know.

like image 114
Jon Skeet Avatar answered Nov 09 '22 19:11

Jon Skeet


You'll normally just want to refer to the base class in that case:

public class Adapter<T> { 
   public virtual Adapter<T> DoSomething();

Trying to do what you're accomplishing violates the Liskov substitution principal.

like image 20
Reed Copsey Avatar answered Nov 09 '22 19:11

Reed Copsey