什么<在TFrom,out TTo>是什么意思?

mht*_*ttk 25 c# generics covariance contravariance

Resharper建议改变

interface IModelMapper<TFrom, TTo>
{
    TTo Map(TFrom input);
}
Run Code Online (Sandbox Code Playgroud)

interface IModelMapper<in TFrom, out TTo>
Run Code Online (Sandbox Code Playgroud)

所以我调查了一下,结束了阅读这篇文章(通过维基百科的文章找到)和更多的谷歌.

我仍然不确定这对我的申请意味着什么,所以我很想接受这个建议.这种改变会带来什么好处,我不考虑忽视这个建议?

更明确的是,我为什么要接受它?

Ada*_*kis 48

结论: Resharper调查了你的类型,并发现它TFrom可能会被反复使用,并且可以协同使用TTo.接受重构将允许您更灵活地使用这些类型,如下所述.如果这对您有价值,请接受它.

但请注意,接受此重构将限制您将来如何使用这些类型.如果您编写一个TTo以参数形式出现的方法,则会出现编译错误,因为无法读入协同类型.并且同样适用于TFrom:您将永远无法拥有返回此类型的方法,或者具有out这种类型的参数.


这告诉你这TFrom是逆变的,这TTo是协变的.这些是最近添加到C#的功能

类型协方差意味着可以传入具体的类型,而逆变意味着可以传递更不具体的类型.

IEnumerable<T>类型协方差是一个很好的例子.由于a中的项目IEnumerable<T>只读的,您可以将其设置为更具体的内容:

IEnumerable<object> objects = new List<string>();
Run Code Online (Sandbox Code Playgroud)

考虑如果(假设)允许您对读/写集合执行此操作会发生什么:

List<object> objects = new List<string>();
objects.Add(new Car());
//runtime exception
Run Code Online (Sandbox Code Playgroud)

要成为类型协变,必须以严格只读的方式使用泛型参数; 它必须只从类型中写出来,并且永远不会读(因此关键字).这就是该IEnumerable<T>示例有效的原因,但List<T>示例没有.顺便说一下,数组确实支持类型协方差(因为Java确实如此),因此数组可能会出现同样的运行时错误.

类型逆变意味着相反.为了支持型逆变泛型参数必须读只是,从来没有写出来.这允许您替换较少的特定类型.

Action<T> 是类型逆转的一个例子:

Action<object> objAction = (o => Console.WriteLine(o.ToString()));
Action<string> strAction = objAction;
strAction("Hello");
Run Code Online (Sandbox Code Playgroud)

strAction声明采用字符串参数,但如果替换对象类型,它可以正常工作.一个字符串将被传入,但如果它设置为使用的委托选择将其视为一个对象,那么就这样吧.没有伤害.

为了完整性,Func<T>是相反的情况Action<T>; 这里T只返回,因此它是协变的:

Func<string> strDelegate =  () => "Hello";
Func<object> myObjFunc = strDelegate;
object O = myObjFunc();
Run Code Online (Sandbox Code Playgroud)

myObjectFunc被编码为返回一个对象.如果将其设置为返回字符串的内容,那么再次,不会造成任何损害.