简体   繁体   中英

Action<T> or Action<in T>?

I was reading about Action Delegate on MSDN and so this under syntax

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

Than I looked in c-sharpcorner.com and it used this syntax

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

As you can see there is no in before T.
Which syntax is right and what does that in mean?
EDIT: The same syntax used for Predicate .

Thanks.

in and out (generic contravariance and covariance) were only introduced in C# 4, and the delegates and interfaces were modified for .NET 4 - so Action<T> in .NET 3.5 became Action<in T> in .NET 4.

The article you're referring to is from 2006, well before .NET 4 came out.

If you change which version of MSDN you're displaying, you'll see the change - for example, the .NET 3.5 version shows it without the in .

in部分是协方差和逆变 ,并介绍了在.NET 4.0中,你链接到被刊登在2006年之前,.NET 4.0的文章被释放(所以显然它并不是指合作[NTRA]方差)。

It may be worth noting that conceptually all delegate types could in theory be inherently covariant with any type parameter used only as the return type and contravariant with regard to type parameters used only for method parameters passed by value, and compilers could automatically allow for such variance, except for one problem: while the in declaration of Action will prevent the compiler from squawking if an Action<Animal> is passed to a method that expects an Action<Cat> , some methods that expect an Action<Cat> may behave very badly if given an Action<Animal> . In general, methods which should only accept delegates of types with covariance/contravariance specifiers if they will work correctly with all such delegates; otherwise they should accept delegate types without such specifiers.

Most methods which accept an Action<Cat> will work just fine with an Action<Animal> , so Microsoft decided retroactively to make Action<T> contravariant. Because many methods which accept an EventHandler<T> could fail very badly if given anything that didn't perfectly match the expected type, EventHandler<T> was not made contravariant.

In retrospect, if each delegate type had defined its own Combine method, it would have been possible to make delegate covariance and contravariance work in almost all cases. If CatEventArgs:AnimalEventArgs , saying

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

could have turned a passed-in EventHandler<AnimalEventsArgs> into an EventHandler<CatEventArgs> , which could then be combined with any other delegate that could likewise be converted into an EventHandler<CatEventArgs> . Unfortunately, since Combine was only defined on Delegate , there's no way by which the Combine method can know what delegate type is needed by the calling code [IMHO, even without covariance/contravariance, it would have been nice to have delegates define their own Combine and Remove methods, since that would have avoided the need to typecast the result of Delegate.Combine ].

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM