开发者

Action<T> or Action<in T>?

开发者 https://www.devze.com 2023-01-22 20:16 出处:网络
I was reading about Action Delegate on MSDN and so this under syntax public delegate void Action<in T>(T obj);

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: Th开发者_StackOverflow社区e 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.


The in part is for covariance and contravariance and was introduced in .NET 4.0, the article you link to was published in 2006 before .NET 4.0 was released (so obviously it doesn't refer co[ntra]variance).


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].

0

精彩评论

暂无评论...
验证码 换一张
取 消