2009-09-17 3 views
3

Я хотел иметь хэш-таблицу со строкой в ​​качестве ключа и функцию-указатель (делегат) в качестве значения. Этот способ вызывает правильную процедуру, заданную строковой командой. Однако компилятор его не съест.Как использовать коллекцию для хранения делегата?

Что я делаю неправильно?

//declaration 
    public delegate void categoryHandler(String request);  

//init code 
    Hashtable categories = new Hashtable(); 
    categories.Add("campaigns", Campaigns.post); 

//function call 
    String category = "campaigns"; 
    categoryHandler handler = (categoryHandler) categories[category]; 
    if (handler != null) 
    { 
      handler(someString); 
    } 

//handler 
    static public void post(String request) 
    { 
      ... 
    } 

Я получаю ошибку на линии, где я поставил функцию в хэш-таблице: Ошибка 2 Аргумент «2»: не удается преобразовать из «группы методов» до «объекта»

Я надеясь, что это просто какая-то семантическая штука, которую я забыл ... Но если этого не может быть сделано ... есть ли другой способ иметь какой-то String-based jumptable?

+0

Какую версию .NET и C# вы используете? – thecoop

ответ

8

Проблема в том, что вы используете Hashtable, который слабо типизирован. Компилятор видит группу методов (имя метода, который вы хотите преобразовать в делегат), но не знает, какой тип делегата вы имеете в виду.

Если вы хотите продолжать использовать Hashtable, вы могли бы сделать:

categoryHandler handler = Campaigns.post; 
categories.Add("campaigns", handler); 

или

categories.Add("campaigns", new categoryHandler(Campaigns.post)); 

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

Однако лучшим решением является использование Dictionary<string, categoryHandler> в первую очередь - всегда используйте строго типизированные коллекции, где вы можете разумно сделать это (что почти всегда). Ради соглашения, это должно быть CategoryHandler btw - это имя типа. Аналогично post должно быть Post.

Тогда назвать это, вы будете использовать:

String category = "campaigns"; 
CategoryHandler handler; 
if (categories.TryGetValue(category, out handler)) 
{ 
    handler(someString); 
} 
+0

Хотя я задаюсь вопросом, не будет ли это просто работать с 'HashTable'. В конце концов, 'Delegate' * does * наследует от' Object'. – Joey

+0

... Я никогда не понимал, что в словарях есть «TryGetValue» ...Все это время я делал, если (dict.ContainsKey (foo)) {dict [foo]} ... dang. – GWLlosa

+0

@Johannes: Редактирование, чтобы объяснить, почему он терпит неудачу. –

0

В зависимости от версии C#, который вы используете, возможно, потребуется сделать следующее:

categories.Add("campaigns", new categoryHandler(Campaigns.post)); 

Как и в сторону, если вы используете .NET 2.0 или выше, вы должны использовать общий Dictionary<T,T> класс вместо Hashtable.

1

Не используйте хеш использовать словарь

Ваш код будет меняться тоже.

//declaration 
    public delegate void categoryHandler(String request);  

//init code 
    Dictionary<string, categoryHandler> categories = new Dictionary<string, categoryHandler> ; 
    categories.Add("campaigns", Campaigns.post); 

//function call 
    string category = "campaigns"; 

    if (!categories.ContainsKey(category)) 
    { 
     // Key not there just return 
     return; 
    } 

    categoryHandler handler = categories[category]; // NO need to cast here 

    if (handler != null) 
    { 
      handler(someString); 
    } 

//handler 
    static public void post(String request) 
    { 
      ... 
    } 
+0

Хотя нет необходимости бросать, словарь-индексатор будет генерировать исключение, если ключ не является вместо того, чтобы возвращать null. –

+0

Это правда. Я изменю. –

2

Если вы используете .NET 3.5, вы можете делать то, что я делаю, когда хочу, чтобы исключить заявления переключателя:

private readonly Dictionary<string, Action<string>> _lookupTable = new Dictionary<string, Action<string>> 
{ 
    {"campaigns", post} 
    {"somethingElse", doSomethingElse} 
    {"tryIt", val => doSomethingWithVal(val)} 
}; 

то, где я хотел бы иметь переключатель заявление, я хотел бы сделать это :

_lookupTable["foo"]("bar"); 
+0

очень компактное и читаемое решение! – Toad

Смежные вопросы