РЕДАКТИРОВАТЬ: Хорошо, теперь я вижу, что вы пытаетесь сделать. Я оставил старый ответ ниже для потомков:)
К сожалению, вы не можете выразить желаемую взаимосвязь в дженериках C #, но так как вы можете быть уверены, что вы единственный, кто манипулирует коллекцией, вы можете сохранить ее самостоятельно:
Попробуйте это:
class App
{
private readonly Dictionary<Type, object> delegateMap;
void Add<T>(Action<SomeClass<T>> foo)
{
object tmp;
if (!delegateMap.TryGetValue(typeof(T), out tmp))
{
tmp = new List<Action<SomeClass<T>>>();
delegateMap[typeof(t)] = tmp;
}
List<Action<SomeClass<T>> list = (List<Action<SomeClass<T>>) tmp;
list.Add(foo);
}
void InvokeActions<T>(SomeClass<T> item)
{
object tmp;
if (delegateMap.TryGetValue(typeof(T), out tmp))
{
List<Action<SomeClass<T>> list = (List<Action<SomeClass<T>>) tmp;
foreach (var action in list)
{
action(item);
}
}
}
}
Обратите внимание, что вы могли бы использовать тот факт, что делегаты являются многоадресными, чтобы просто сохранить Dictionary<Type, Delegate>
и объединить их вместе, но я оставлю это в качестве упражнения для читателя:
Старый ответ
Это не удачно по уважительной причине. Давайте избавимся от дженериков (поскольку они здесь неактуальны) и подумаем о более простом случае - фруктах и бананах.
Вы пытаетесь добавить Action<Banana>
к List<Action<Fruit>>
. Вы не можете сделать это - даже с общей дисперсией C # 4. Почему? Потому что это не безопасно. Учтите это:
Action<Banana> peeler = banana => banana.Peel();
List<Action<Fruit>> fruitActions = new List<Action<Fruit>>();
fruitActions.Add(peeler); // Nope!
fruitActions[0].Invoke(new Strawberry());
Ик! Теперь у нас есть банановый нож, который пытается очистить клубнику ... какой беспорядок!
Не то, чтобы другие обходные пути были бы приемлемы в C # 4:
Action<Fruit> eater = fruit => fruit.Eat();
List<Action<Banana>> bananaActions = new List<Action<Banana>>();
fruitActions.Add(eater); // Yes!
fruitActions[0].Invoke(new Banana());
Здесь мы добавляем Action<Fruit>
к List<Action<Banana>>
- это приемлемо, потому что все, что вы можете сделать с Action<Banana>
, также действует для Action<Fruit>
.