Изменить действие C # / цель делегата: иерархические вызовы

2

Предположим, что

public IList<Entity> Children { get; set; }

public NotifyChildren(Func<object, bool> action, object data)
{
   foreach (var child in Children)
       if (action(data))
           /// <-- !!!! need action to work on child this time, not on the original target
           //child.NofifyChildren(action, data); <- this doesn't work because of the above requirement
           child.NotifyChildren(action.ChangeTargetTo(child), data); // << pseudocode!
}

public void SomeChangeOccured()
{
   var changedChild;
   NotifyChildren(x => x.SomeHandler(), "somedata");
}

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

public NotifyChildren(Expression<Func<Entity, bool>> action, object data)
{
     // so that I can do method.Invoke(newtarget, new object[]{data});
     NotifyChildren(((MethodCallExpression)action).Method, data);
}

то есть перейти от действия к отраженному вызову метода... но он бит уродливый, не так ли?

У меня такое ощущение, что решение очень простое, и я его знал... просто забыл.

Hm, одно решение должно состоять в том, чтобы иметь статический делегат, который принимает Entity в качестве первого параметра, но я бы не хотел идти этим путем.

  • 0
    Ваш пример кода находится в классе с именем Entity?
  • 0
    На самом деле он находится в классе Parent, но это не имеет значения. В этом примере я написал его так, как будто он находится в классе Child.
Показать ещё 1 комментарий
Теги:

2 ответа

4
Лучший ответ

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

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

Вы определяете action как Func<Entity, bool>, но вы передаете data (который является object), а не child (который является Entity). Похоже, вы должны объявить его как Func<Entity, object, bool> и сделать это следующим образом:

public IList<Entity> Children { get; set; }

public NotifyChildren(Func<Entity, object, bool> action, object data)
{
   foreach (var child in Children)
   {
       if (action(child, data))
       {
           child.NofifyChildren(action, data); 
       }
   }
}

public void SomeChangeOccured()
{
     NotifyChildren((x, data) => x.SomeHandler(data), "somedata");
}

public bool SomeHandler(object data)
{
     return true; // obviously need more robust logic
}
  • 1
    На самом деле это возможно с несвязанными делегатами, но ваше решение кажется лучше в этом случае. FWIW, вы также можете создать делегата прямо из SomeHandler если вы не возражаете получить его MethodInfo с отражением.
  • 0
    Я исправил подпись. То, что вы предоставили, не сработает, поскольку действие все равно будет работать с исходной сущностью верхнего уровня - мне нужно, чтобы оно вызывалось для дочернего элемента. Вы вызываете действие (дочерний элемент, данные), но я не хочу использовать метод «статический делегат» (передача его в качестве первого метода статической функции).
Показать ещё 3 комментария
0
foreach (var child in Children)
   if (action(data))
       /// <-- !!!! need action to work on child this time, not on the original target
       child.NofifyChildren(action, data); 

ПОЧЕМУ вы вызываете действие в этом цикле? Я думаю, вы можете назвать это только один раз перед тем, как отправиться.

  • 0
    Потому что мне нужно ;-) действие здесь - это просто имя метода, скажем «HandleNameChange». И я хочу назвать это для всех детей, и если дети решат, они хотят назвать это для своих детей. Это своего рода пузырьковая передача событий.
  • 0
    где вы передаёте детям экземпляр к действию в этом звонке?
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню