Страницы

Поиск по вопросам

пятница, 20 декабря 2019 г.

Ковариантность и контрвариантность в делегатах Action и Func [дубликат]

#c_sharp #action #делегаты


        
             
                
                    
                        
                            This question already has answers here:
                            
                        
                    
                
                        
                            В чем суть ковариантности и контравариантности делегатов?
                                
                                    (2 ответа)
                                
                        
                                Закрыт 2 года назад.
            
                    
Почему параметры T1, T2,... являются контрвариантными (in T1, in T2,...) в Action? 

И почему возвращаемый тип в Func является ковариантным (out TResult)? 
    


Ответы

Ответ 1



На пальцах: если вам требуется парикмахер для собак (Action), подойдёт универсальный парикмахер для животных (функция, принимающая на вход Animal). Поэтому переменной типа Action можно присвоить выражение типа Action. Наоборот, если вам нужно раздобыть какое угодно животное (Func), то магазин по продаже котяток подойдёт (Func). Поэтому переменной типа Func можно присвоить выражение типа Func. Более подробно: В чем суть ковариантности и контравариантности делегатов?, Контравариантность обобщенных делегатов С#.

Ответ 2



Делегаты Action контрвариантны потому что там, где вы можете использовать экземпляр класса-предка, там же вы можете использовать и экземпляр потомка. Пример: Action act1 = str => { int i = str.Length; }; Action act2 = o => { string s = o.ToString(); }; // вы можете сделать такое присваивание act1 = act2; // и затем вызвать делегат вот так, // потому что по факту у вас будет вызван 2-ой делегат, // которому будет передана string, производная от object act1("10"); Так как string - наследник object, то вы можете делать с этим параметром всё то же, что и с object. Ошибки нет. При этом вы не можете сделать так: act2 = act1; Потому что в этом случае вы смогли бы передать некий object в метод, требующий на самом деле string, а это уже ошибка. Схожим образом объясняется и ковариантность Func: Func func1 = () => "str"; Func func2 = () => 10; // такое присваивание тоже возможно func2 = func1; // ваш делегат вернёт некий object, который по факту является строкой. object r = func2(); Аналогично предыдущему примеру, нельзя делать так: func1 = func2; так как в этом случае делегату, возвращающему string, вы можете присвоить делегат, возвращающий object (который в нашем примере фактически имеет тип int).

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

Отправить комментарий