views:

355

answers:

2

I bumped into an additional question that I needed in regards to this: http://stackoverflow.com/questions/1099729/using-an-ienumerablet-as-a-delegate-return-type

From the above solution, the following was suggested:

class Example
{
    //the delegate declaration
    public delegate IEnumerable<T> GetGridDataSource<T>();

    //the generic method used to call the method
    public void someMethod<T>(GetGridDataSource<T> method)
    {
        method();
    }

    //a method to pass to "someMethod<T>"
    private IEnumerable<string> methodBeingCalled()
    {
        return Enumerable.Empty<string>();
    }

    //our main program look
    static void Main(string[] args)
    {
        //create a new instance of our example
        var myObject = new Example();
        //invoke the method passing the method
        myObject.someMethod<string>(myObject.methodBeingCalled);
    }
}

Notice that in someMethod, the delegate "method()" is called. Is there anyway to set a class-level delegate that is called later on?

I.e:

 class Example {
    //the delegate declaration
    public delegate IEnumerable<T> GetGridDataSource<T>();

    //this fails because T is never provided
    private GetGridDataSource<T> getDS;

    //the generic method used to call the method
    public void someMethod<T>(GetGridDataSource<T> method)
    {
        getDS = method;
    }

    public void anotherMethod() {
        getDS();
    }
 }
A: 

You either need to make the type generic as well, or use plain Delegate and cast back to the right type when you need to invoke it. You can't just use T outside a generic context - the compiler will think you're trying to refer to a normal type called T.

To put it another way - if you're going to try to use the same type T in two different places, you're going to need to know what T is somewhere in the type... and if the type isn't generic, where is that information going to live?

Jon Skeet
+2  A: 

Depending on what you are trying to achieve and where you have flexibility in your design, there are a number of options. I've tried to cover the ones that I feel most probably relate to what you want to do.

Multiple values of T in a single instance of a non-generic class

This is basically what you seem to want. However, because of the generic nature of the method call, you'll need a class level variable that can support any possible value of T, and you will need to know T when you store a value for the delegate.

Therefore, you can either use a Dictionary<Type, object> or you could use a nested type that encapsulates the class-level variable and the method, and then use a List<WrapperType<T>> instead.

You would then need to look up the appropriate delegate based on the required type.

class Example {
    //the delegate declaration
    public delegate IEnumerable<T> GetGridDataSource<T>();

    //this works because T is provided
    private Dictionary<Type, object> getDSMap;

    //the generic method used to call the method
    public void someMethod<T>(GetGridDataSource<T> method)
    {
        getDSMap[typeof(T)] = method;
    }

    //note, this call needs to know the type of T
    public void anotherMethod<T>() {
        object getDSObj = null;
        if (this.getDSMap.TryGetValue(typeof(T), out getDSObj))
        {
            GetGridDataSource<T> getDS = getDSObj as GetGridDataSource<T>;
            if (getDS != null)
              getDS();
        }
    }

Single value of T in a single instance of a non-generic class

In this case, you could store the delegate instance in a non-typed delegate and then cast it to the appropriate type when you need it and you know the value of T. Of course, you'd need to know T when you first create the delegate, which negates the need for a generic method or delegate in the first place.

Multiple values of T in multiple instances of a generic class

Here you can make your parent class generic and supply T up front. This then makes the example you have work correctly as the type of T is known from the start.

class Example<T> {
    //the delegate declaration
    public delegate IEnumerable<T> GetGridDataSource<T>();

    //this works because T is provided
    private GetGridDataSource<T> getDS;

    //the generic method used to call the method
    public void someMethod<T>(GetGridDataSource<T> method)
    {
        getDS = method;
    }

    public void anotherMethod() {
        if (getDS != null)
          getDS();
    }
 }
Jeff Yates