How to create a cross reference with generics?  
Author Message
juergen.b





PostPosted: Visual C# Language, How to create a cross reference with generics? Top

Is it possible to create a cross reference with generics I have a nice example where I should have such a feature:

public interface IInterceptor<T> where T : DefaultInvocation<IInterceptor<T>>
{
object Invoke(T invocation);
}

public abstract class DefaultInvocation<T> where T : IInterceptor<DefaultInvocation<T>>
{
IList<T> interceptors;
int currentIndex = 0;

public DefaultInvocation(IList<T> interceptors)
{
this.interceptors = interceptors;
}

public object Proceed()
{
object retVal = null;

if (currentIndex < interceptors.Count)
{
retVal = interceptors[currentIndex].Invoke(
this);
currentIndex++;
}

return retVal;
}
}

thx for any answer, JBE



Visual C#17  
 
 
Mads Torgersen - MSFT





PostPosted: Visual C# Language, How to create a cross reference with generics? Top

You've hit a really juicy type issue that only a few research languages in the world deal with completely. The issue is that of describing a set of mutually dependent types in the abstract, which can then be specialized together.

You can almost describe that with C# generics. The trick is to parameterize both your types over both the types in the "group", or more generally, all the n types over all n types!

Of course this gets annoying and repetitive. A good trick is to wrap all the interdependent abstract types in a single generic class that has all the parameters.

The final issue (the reason for the "almost" above) is a little snag around the type of "this", which I'll return to. Here's how I'd do your thing:

public class Interceptor<TInterceptor,TInvocation>

where TInterceptor : Interceptor<TInterceptor,TInvocation>.IInterceptor

where TInvocation : Interceptor<TInterceptor,TInvocation>.DefaultInvocation

{

public interface IInterceptor {

object Invoke(TInvocation invocation);

}

public abstract class DefaultInvocation {

IList<TInterceptor> interceptors;

int currentIndex = 0;

public DefaultInvocation(IList<TInterceptor> interceptors) {

this.interceptors = interceptors;

}

public object Proceed() {

object retVal = null;

if (currentIndex < interceptors.Count) {

retVal = interceptors[currentIndex].Invoke(this as TInvocation);

currentIndex++;

}

return retVal;

}

}

}

The catch is the call of Invoke, where we have to cast the current object to TInvocation. Fancy languages such as Scala have ways to avoid having to do that.

Hope this helps get you started!