Событие и контравариантность делегата в.NET 4.0 и C# 4.0

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

Класс:

...

protected void APrivateFunction()
{
    ...
}

...

Подкласс для тестирования:

...

[Test]
public void TestAPrivateFunction()
{
    APrivateFunction();
    //or whatever testing code you want here
}

...
28
задан Community 23 May 2017 в 12:33
поделиться

2 ответа

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

Рассмотрим Func и Func . В C # 4.0 вы можете неявно преобразовать Func в Func , потому что вы всегда можете использовать строковую ссылку как ссылку на объект. Однако, когда вы пытаетесь их объединить, все идет не так. Вот короткая, но полная программа, демонстрирующая проблему двумя разными способами:

using System;

class Program
{    
    static void Main(string[] args)
    {
        Func<string> stringFactory = () => "hello";
        Func<object> objectFactory = () => new object();

        Func<object> multi1 = stringFactory;
        multi1 += objectFactory;

        Func<object> multi2 = objectFactory;
        multi2 += stringFactory;
    }    
}

Компилируется нормально, но оба вызова Combine (скрытые синтаксическим сахаром + =) вызывают исключения. (Закомментируйте первую, чтобы увидеть вторую.)

Это определенно проблема, хотя я не совсем уверен, каким должно быть решение. Возможно, что во время выполнения код делегата должен будет разработать наиболее подходящий тип для использования на основе задействованных типов делегатов. Это немного противно. Было бы неплохо иметь общий вызов Delegate.Combine , но вы не могли бы выразить соответствующие типы осмысленным образом.

Стоит отметить одну вещь: ковариантное преобразование - это преобразование ссылок - в приведенном выше примере multi1 и stringFactory относятся к одному и тому же объекту: это не то же самое, что и запись

Func<object> multi1 = new Func<object>(stringFactory);

(в этот момент следующее строка будет выполняться без исключения.) Во время выполнения BCL действительно должен иметь дело с объединением Func и Func ; у него нет другой информации, чтобы продолжить.

Это неприятно, и я серьезно надеюсь, что это каким-то образом будет исправлено. Я предупрежу Мэдса и Эрика об этом вопросе, чтобы мы могли получить более информированный комментарий.

9
ответ дан 28 November 2019 в 03:56
поделиться

Получаете ли вы исключение ArgumentException от обоих? Если исключение генерируется только новым обработчиком, то я бы подумал, что оно обратно совместимо.

Кстати, я думаю, вы перепутали ваши комментарии. В C # 3.0 это:

button.Click + = new EventHandler (button_Click); // old

не запустился бы. Это C # 4.0

0
ответ дан 28 November 2019 в 03:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: