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

Type of theoretical question. Quite a long time, so feel free to skip if you're not in the mood for theory.

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

Like this (note in the text):

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

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

      

I cannot do this because there is no way to refer to a private type that would be inferred from a generic type. (Sorry for the broken language, I just don't know how to express it.) There is no keyword instead ???

to indicate that this method will return an instance of a type that will be derived from this generic type.

Instead, I can use a workaround to explicitly pass the type name to the shared base. But it looks overkill.

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 the members of the instance TThis

, I have to add a constraint. It looks ugly this time - notice the limitation:

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, everything works, but it would be better if I could just use some keyword instead ???

in the first piece of code. Something like " thistype ".

Do you think this will work? This is useful? Or maybe it's just silly?

+2


source to share


4 answers


There is nothing that simplifies this pattern, and in fact the pattern is not entirely bulletproof as you might have:

class TypeA : Adapter<TypeA, string>

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

      

The second line here is completely legal - it TypeA

is a valid type argument for the type parameter TThis

, although this is not what we wanted. In principle, the type system does not allow us to express the notion "T must be this type".

I disagree with those who say this is bad or useless. I found Protocol Buffers helpful (if difficult) - it would be much worse with that. For example:



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

      

does not work unless Foo.Build()

it was strongly typed to return Foo

, although the method Build

is specified in IBuilder<...>

.

It is worth avoiding this if you can easily simply because it gets so complex, but I think it is a useful pattern to know.

+8


source


Usually, you just want to refer to the base class:

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

      



Trying to do what you are doing violates the Liskov substitution principle .

+4


source


If an inherited method in a derived class is to return a derived type instead of a base type (known as a covariant return type ), this is already supported in C #.

-1


source


I also find it hard to find a controversial use case (although it's an interesting idea).

Are you trying to move from how you restrict what generic types you can use? It sounds like you want to accept some basic functionality without knowing the actual type; that's what interfaces are for . The where clause is pretty handy for such problems.

class Dictionary<K, V>
where K : IComparable, IEnumerable
where V : IMyInterface
{
    public void Add(K key, V val)
    {
    }
}

      

The above example constrains K (key) so that it must be comparable and enumerable, and V must implement whatever client functionality you want through its own interface.

-1


source







All Articles