Действие <T>или Действие? - PullRequest
10 голосов
/ 02 ноября 2010

Я читал о Action Delegate на MSDN и так под синтаксисом

 public delegate void Action<in T>(T obj);

Чем я заглянул в c-sharpcorner.com и он использовал этот синтаксис

public delegate void Action<T>(T obj);   

Как видите, до T * in нет.
Какой синтаксис правильный и что означает in? 1014 * РЕДАКТИРОВАТЬ: тот же синтаксис, который используется для Predicate.

Спасибо.

Ответы [ 3 ]

10 голосов
/ 02 ноября 2010

in и out (общая контравариантность и ковариация) были введены только в C # 4, а делегаты и интерфейсы были изменены для .NET 4 - поэтому Action<T> в .NET 3.5 стал Action<in T> в .NET 4.

Статья, на которую вы ссылаетесь, написана в 2006 году, задолго до выхода .NET 4.

Если вы измените отображаемую версию MSDN, вы увидите это изменение - например, .NET 3.5 версия показывает ее без in.

9 голосов
/ 02 ноября 2010

Часть in предназначена для ковариации и контравариантности и была представлена ​​в .NET 4.0, статья, на которую вы ссылаетесь, была опубликована в 2006 году до выпуска .NET 4.0 (так что, очевидно, она не относится совместно [NTRA] дисперсия).

1 голос
/ 09 октября 2013

Стоит отметить, что концептуально все типы делегатов теоретически могут быть по своей природе ковариантными с любым параметром типа, используемым только в качестве возвращаемого типа, и контравариантным относительно параметров типа, используемых только для параметров метода, передаваемых по значению, и компиляторы могут автоматически разрешатьдля такой дисперсии, за исключением одной проблемы: в то время как объявление in для Action предотвратит писк компилятора, если Action<Animal> передается методу, который ожидает Action<Cat>, некоторые методы ожидают Action<Cat>может вести себя очень плохо, если дано Action<Animal>.В общем случае, методы, которые должны принимать делегатов типов только со спецификаторами ковариации / контравариантности, если они будут корректно работать со всеми такими делегатами;в противном случае они должны принимать типы делегатов без таких спецификаторов.

Большинство методов, которые принимают Action<Cat>, будут прекрасно работать с Action<Animal>, поэтому Microsoft решила задним числом сделать Action<T> контравариантным,Поскольку многие методы, которые принимают EventHandler<T>, могут очень сильно потерпеть неудачу, если дано что-либо, что не полностью соответствует ожидаемому типу, EventHandler<T> не был сделан контравариантным.

В ретроспективе, если каждый тип делегата определил егособственный метод Combine, было бы возможно заставить ковариацию делегата и контравариантность работать почти во всех случаях.Если CatEventArgs:AnimalEventArgs, сказав

EventHandler<CatEventArgs> myEvents=null;
void AddEvent(EventHandler<CatEventArgs> newEvent)
{
  myEvents = EventHandler<CatEventArgs>.Combine(myEvents, newEvent);
}

, можно было бы превратить переданный EventHandler<AnimalEventsArgs> в EventHandler<CatEventArgs>, который затем можно было бы объединить с любым другим делегатом, который также мог бы быть преобразован в EventHandler<CatEventArgs>,К сожалению, поскольку Combine был определен только для Delegate, нет способа, с помощью которого метод Combine может узнать, какой тип делегата необходим вызывающему коду [IMHO, даже без ковариации / контравариантности было бы неплохопусть делегаты определяют свои собственные методы Combine и Remove, поскольку это позволило бы избежать необходимости типизации результата Delegate.Combine].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...