Установка общего делегата для переменной уровня класса - PullRequest
1 голос
/ 08 июля 2009

Я столкнулся с дополнительным вопросом, который мне был нужен в отношении этого: Использование IEnumerable в качестве типа возврата делегата

Из приведенного выше решения было предложено следующее:

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);
    }
}

Обратите внимание, что в someMethod вызывается делегат "method ()". Есть ли способ установить делегат уровня класса, который будет вызываться позже?

т.е:

 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();
    }
 }

Ответы [ 2 ]

2 голосов
/ 08 июля 2009

В зависимости от того, чего вы пытаетесь достичь и где у вас есть гибкость в дизайне, есть несколько вариантов. Я пытался охватить те из них, которые, по моему мнению, наиболее вероятно связаны с тем, что вы хотите сделать.

Несколько значений T в одном экземпляре неуниверсального класса

Это в основном то, что вы, кажется, хотите. Однако из-за общего характера вызова метода вам понадобится переменная уровня класса, которая может поддерживать любое возможное значение T, и вам нужно будет знать T при сохранении значения для делегата.

Следовательно, вы можете использовать Dictionary<Type, object> или использовать вложенный тип, который инкапсулирует переменную уровня класса и метод, а затем вместо него использовать List<WrapperType<T>>.

Затем вам нужно будет найти соответствующего делегата на основе требуемого типа.

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();
        }
    }

Одно значение T в одном экземпляре неуниверсального класса

В этом случае вы можете сохранить экземпляр делегата в нетипизированном делегате, а затем преобразовать его в соответствующий тип, когда вам это нужно, и вы знаете значение T. Конечно, вам нужно знать T, когда сначала вы создаете делегат, что сводит на нет необходимость в универсальном методе или делегате.

Несколько значений T в нескольких экземплярах универсального класса

Здесь вы можете сделать свой родительский класс родовым и предоставить T заранее. Это затем приводит к тому, что у вас работает правильно, так как тип T известен с самого начала.

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();
    }
 }
0 голосов
/ 08 июля 2009

Вам либо нужно сделать тип обобщенным, либо использовать обычный Delegate и привести обратно к нужному типу, когда вам нужно его вызвать. Вы не можете просто использовать T вне общего контекста - компилятор подумает, что вы пытаетесь сослаться на нормальный тип с именем T.

Другими словами - если вы собираетесь использовать один и тот же тип T в двух разных местах, вам нужно знать, что T находится где-то в этом типе ... и если тип не является общим, где эта информация будет жить?

...