Resharper 建议从
interface IModelMapper<TFrom, TTo>
{
TTo Map(TFrom input);
}
进入
interface IModelMapper<in TFrom, out TTo>
所以我调查了一下并结束阅读this article (通过 Wikipedia 文章找到)和更多 Google。
我仍然不确定这对我的申请意味着什么,所以我很想不接受这个建议。此更改会带来哪些好处,我不会通过忽略该建议来考虑?
更明确地说,我为什么要接受它?
最佳答案
底线:Resharper 已调查您的类型,并发现 TFrom
可以逆变地使用,并且TTo
协变地。接受重构将使您能够更灵活地使用这些类型,如下所述。如果这可能对您有值(value),请接受它。
但是请注意,接受此重构会限制您将来如何使用这些类型。如果你曾经写过一个接受 TTo
的方法作为参数,你会得到一个编译器错误,因为无法读入协变类型。TFrom
也是如此。 : 你将永远无法拥有返回此类型或具有 out
的方法这种类型的参数。
这告诉你 TFrom
是逆变的,并且TTo
是协变的。这些是最近的功能 added to C#
类型协变意味着可以传入更多特定类型,而逆变意味着可以传入更少特定类型。
IEnumerable<T>
是类型协变的一个很好的例子。由于 IEnumerable<T>
中的项目是只读,您可以将其设置为更具体的内容:
IEnumerable<object> objects = new List<string>();
考虑如果(假设地)您被允许对可读/写的集合执行此操作会发生什么:
List<object> objects = new List<string>();
objects.Add(new Car());
//runtime exception
要成为类型协变,泛型参数必须以严格的只读方式使用;它只能从类型中写出 out,永远不要读入 in(因此是关键字)。这就是为什么 IEnumerable<T>
示例有效,但是 List<T>
例子没有。顺便说一句,数组确实支持类型协变(我相信 Java 支持),因此数组也可能出现同样类型的运行时错误。
类型逆变意味着相反。为了支持类型逆变,泛型参数必须只被读入in,而绝不能写出。这允许您替换不太具体的类型。
Action<T>
是类型违背的一个例子:
Action<object> objAction = (o => Console.WriteLine(o.ToString()));
Action<string> strAction = objAction;
strAction("Hello");
strAction
被声明为采用字符串参数,但如果您替换为对象类型,它就可以正常工作。一个字符串将被传入,但如果它被设置为与之一起工作的委托(delegate)选择将其视为一个对象,那么就这样吧。没有伤害。
为了完整性,Func<T>
是 Action<T>
的相反情况;这里T
仅返回,因此它是协变的:
Func<string> strDelegate = () => "Hello";
Func<object> myObjFunc = strDelegate;
object O = myObjFunc();
myObjectFunc
被编码为返回一个对象。如果您将其设置为返回字符串的内容,那么同样不会造成任何伤害。
关于c# - <in From, out To> 是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8317186/