2010-11-02 2 views
10

Я читал об действиях делегата на MSDN и так это под синтаксисомДействие <T> или Действие <in T>?

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

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

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

Как вы можете видеть, что нет in перед тем Т.
Какой синтаксис правильный и что означает это in?
EDIT: тот же синтаксис, используемый для Predicate.

Спасибо.

ответ

9

in part is for covariance and contravariance и был представлен в .NET 4.0. Статья, ссылка на которую вы указали, была опубликована в 2006 году, прежде чем был выпущен .NET 4.0 (поэтому, очевидно, это не относится к co [ntra] variance).

10

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

статья, о которой вы говорите, - с 2006 года, задолго до выхода .NET 4.

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

0

Может быть, стоит отметить, что концептуально все типы делегатов теоретически может быть по своей сути ковариантны с любым типом параметра используется только в качестве возвращаемого типа и контрвариантным в отношении к типу параметров, используемых только для параметров методов, передаваемых по значению, и компиляторы может автоматически допускают такую ​​дисперсию, за исключением одной проблемы: в то время как объявление 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].