Feature request for C# Generic inheritence

  • Thread starter Thread starter Ido Samuelson
  • Start date Start date
I

Ido Samuelson

Hello,

What do you think about the following features:

public class GenericDecorator<T> : T
{

}

can leverage to a few things:

public interface IChannel
{
void Connect();
void Disconnect();
}

public class TcpChannel : IChannel
{
....
}

public class ChannelDescriber<T> : T where T : IChannel, class
{
public string ChannelName {get; set;}
}

another more complicated example:

public class Extender<T,K> : T
{
public K Data {get;set;}
}

which can be use to :
Extender<EventArgs,string> extender;

extender.Data (give the same ability as EventArgs<T> but more generic which can leverage other types that do not support generics.

Last is for delegates aka

delegate void extendDelegate<T,K>(K t) : T where T : delegate
// K should be added as first parameter.
and usage:

extendDelegate<ThreadStart,string> Start;

Start("hello world");

which means that even further we can do this:

System.Threading.Thread.Start(Start("ido",null)); // anonymous delegates feature

void Start(string name, object state);

you can vote for the feature in the following like:
https://connect.microsoft.com/Visua...Feedback.aspx?FeedbackID=299676&wa=wsignin1.0
 
The trouble is that .NET generics, unlike C++ templates, are completely
compiled in generic form. However, all base classes must be known at
compile time. Only C++ templates, which are made concrete before being
compiled, can inherit from template parameters. However .NET classes can
use the curiously recurring template pattern which has some overlapping
applications.



Hello,

What do you think about the following features:

public class GenericDecorator<T> : T
{

}

can leverage to a few things:

public interface IChannel
{
void Connect();
void Disconnect();
}

public class TcpChannel : IChannel
{
....
}

public class ChannelDescriber<T> : T where T : IChannel, class
{
public string ChannelName {get; set;}
}

another more complicated example:

public class Extender<T,K> : T
{
public K Data {get;set;}
}

which can be use to :
Extender<EventArgs,string> extender;

extender.Data (give the same ability as EventArgs<T> but more generic which
can leverage other types that do not support generics.

Last is for delegates aka

delegate void extendDelegate<T,K>(K t) : T where T : delegate
// K should be added as first parameter.
and usage:

extendDelegate<ThreadStart,string> Start;

Start("hello world");

which means that even further we can do this:

System.Threading.Thread.Start(Start("ido",null)); // anonymous delegates
feature

void Start(string name, object state);

you can vote for the feature in the following like:
https://connect.microsoft.com/Visua...Feedback.aspx?FeedbackID=299676&wa=wsignin1.0
 
This is correct. I thought that for generic inheritance, the compiler will
create an explicit type at compile time. Same way anonymous method works.
 
Ido Samuelson said:
This is correct. I thought that for generic inheritance, the compiler will
create an explicit type at compile time. Same way anonymous method works.


No, compiler creates a special "generic" IL using concept of "type erasure".
JIT converts it to machine code. There is only one copy of compiled machine
code shared for all types T (T being the generic argument) as long as T is a
reference type. For value types, JIT compiles it separately to avoid boxing
overhead.

All binding (override resolution) is done knowing only the constraints and
not the final type.

Furthermore, derived classes must share the same v-table ordering of every
superclass. This requires that the base class be known exactly. Here's the
issue:

class Gen<T> : T where T : IList
{
int IList.Count { get { ... } }
}

Let's compare the cases where T is List vs BindingList.

If T is List, then IList.Count.get must appear at the correct v-table offset
according to the inheritance order for List where IList appears, and the
ordinal for the Count getter.

But BindingList derives from Collection. Collection has a different v-table
ordering. It isn't possible to guarantee the same v-table location within
BindingList as within List, because BindingList must start with the same
v-table entries as Collection.

Therefore it isn't possible for a generic class to derive from a generic
parameter.

C++ templates are fully supported in .NET (only using the C++/CLI compiler),
however, and are compiled separately for each combination of parameters.
The result of instantiating a C++ template is a .NET non-generic ref-class.
 
I know how the compiler works for the current generics. I was talking about
how it "will" work for the feature request. So for generic inheritance an
explicit code generated type will be created at compile time. This will
resolve the v-table issue because the base class will be known exactly.

so for your example

class Gen<T> : T where T : IList
{
int IList.Count { get { ... } }
}

at runtime a new type will be created:

Class GenXXXList : List
{
int IList.Count { get {... } }
}

and all the code refered to Gen<T> will be replaced with GenXXXList. (same
way as anonymous methods)
 
Ido Samuelson said:
I know how the compiler works for the current generics. I was talking about
how it "will" work for the feature request. So for generic inheritance an
explicit code generated type will be created at compile time. This will
resolve the v-table issue because the base class will be known exactly.

so for your example

class Gen<T> : T where T : IList
{
int IList.Count { get { ... } }
}

at runtime a new type will be created:

Class GenXXXList : List
{
int IList.Count { get {... } }
}

and all the code refered to Gen<T> will be replaced with GenXXXList. (same
way as anonymous methods)

So a Gen<List> used in one assembly wouldn't the same type as a
Gen<List> in another assembly? Sounds like a recipe for hard-to-
diagnose bugs.
 
isn't that the same case with anonymous methods or extension methods? in
some cases both can cause unexpected behaviors.
 
Further, it is never a good idea to have the same class name, same type and
same namespace in different assemblies. So I really don't see a problem in
debugging.

Ido Samuelson said:
isn't that the same case with anonymous methods or extension methods? in
some cases both can cause unexpected behaviors.
 
Ido Samuelson said:
isn't that the same case with anonymous methods or extension methods? in
some cases both can cause unexpected behaviors.

No - anonymous methods are only accessed within the same type, and
extension methods are completely different anyway.

Anonymous *types* are consistent within an assembly, but that's mostly
an optimisation - you can't expose an API in terms of anonymous types.
 
Ido Samuelson said:
Further, it is never a good idea to have the same class name, same type and
same namespace in different assemblies. So I really don't see a problem in
debugging.

It's completely different to that situation. It's perfectly reasonable
to use List<string> in two different places, but your way of working
would break it. If I were to declare an API of

public Gen<Stream> GetGen()

then the object returned by the method wouldn't be usable in a
different assembly.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top