Неявное приведение к действию

#.net #delegates #casting

#.net #делегаты #Кастинг

Вопрос:

Я использую сторонний библиотечный класс, который имеет следующий (сокращенный) метод:

 public void DoSomethingAsync(Action<ResultInfo> callback)
  

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

 public void MyDoSomethingAsync(Action<MyResultInfo> callback)
{
    this.wrappedClass.DoSomethingAsync(callback);
}
  

Проблема в том, что мне нужно преобразовать callback параметр из Action<MyResultInfo> в Action<ResultInfo> . Возможно ли это с помощью пользовательского оператора неявного приведения или есть альтернативный подход, который кто-нибудь может порекомендовать?

Ответ №1:

Нет, вы не смогли бы сделать это напрямую, даже если бы это было MyResultInfo производным от ResultInfo ; контравариантность делегирования здесь не применялась бы, поскольку Action<MyResultInfo> не смог бы обрабатывать ни один экземпляр, производный от ResultInfo (так что это не позволяет использовать Action<MyResultInfo> вместо Action<ResultInfo> )

Однако это не означает, что вы не можете использовать адаптер, например:

 public void MyDoSomethingAsync(Action<MyResultInfo> callback)
{
    // Create the action which will transform ResultInfo
    // into MyResultInfo and then pass to the wrapped
    // class.
    // Create the action first.
    Action<ResultInfo> a = ri => {
        // Translate ri into MyResultInfo.
        MyResultInfo mri = (translate here);

        // Call the callback with the translated result.
        callback(mri);
    };

    // Pass the action to the wrapped class.
    this.wrappedClass.DoSomethingAsync(a);
}
  

Комментарии:

1. Я склонен не соглашаться с первым утверждением, потому что контравариантность с делегатами работает прямо противоположно, Action<Base> может быть приведена к Action<Derived>

2. Во-вторых, вы связываете точки с контравариантностью неродового делегата, что не работает для Action<T> , контравариантность общего делегата была введена только в .net 4.0.

3. теперь я полностью согласен с вашим ответом. Но я все еще действительно считаю, что это недостаток дизайна в самом вопросе. Был задан вопрос о том, как сделать неправильную вещь.

Ответ №2:

Проблема в том, что то, что вы хотите создать, может привести к несогласованности. Я предполагаю, что это MyResultInfo производное от ResultInfo , потому что в противном случае это не имеет никакого смысла.

Теперь вернемся к несогласованности. Представьте, что у вас есть делегат Action<ResultInfo> callback . Вызывающий код мог бы вызвать это следующим образом: callback(new MyResultInfo()); и вызвать ваш Action<MyResultInfo> , и он будет работать нормально. Но представьте, что это вызывается следующим образом: callback(new ResultInfo()); , Action<ResultInfo> разрешает это, но это приведет к исключению, потому что ResultInfo не может быть приведено к MyResultInfo .