是什么意思?意思是?
Resharper 建议从 更改
interface IModelMapper<TFrom, TTo>
{
TTo Map(TFrom input);
}
为
interface IModelMapper<in TFrom, out TTo>
所以我调查了一下并结束了阅读这篇文章(通过维基百科文章找到)和更多谷歌。
我仍然不确定这对我的申请意味着什么,所以我很想不接受这个建议。如果忽略该建议,我不会考虑此更改会带来哪些好处?
更明确地说,我为什么要接受它?
Resharper has suggested to change from
interface IModelMapper<TFrom, TTo>
{
TTo Map(TFrom input);
}
into
interface IModelMapper<in TFrom, out TTo>
So I investigate a little and ended reading this article (found through a Wikipedia article) and some more Google.
I am still not sure what this would imply for my application so I am tempted of not accepting the suggestion. What would are the benefits this change would introduce and I am not considering by ignoring the suggestion?
More explicitly, why should I accept it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
底线:Resharper 研究了您的类型,并发现
TFrom
可以用于逆变,而TTo
可以用于协变。接受重构将使您能够更灵活地使用这些类型,如下所述。如果这对您有价值,请接受。但请注意,接受此重构将对您将来如何使用这些类型设置限制。如果您编写了一个采用
TTo
作为参数的方法,您将收到编译器错误,因为无法读入协变类型。TFrom
也是如此:您'将永远无法拥有返回此类型的方法,或拥有此类型的out
参数。这告诉您
TFrom
是逆变的,而TTo
是协变的。这些是最近的功能 添加到 C#类型协变意味着可以传入更具体的类型,而逆变意味着可以传入可以传入不太特定的类型。
IEnumerable
是类型协变的一个很好的例子。由于IEnumerable
中的项目是只读,因此您可以将其设置为更具体的内容:考虑如果(假设)会发生什么您可以对读/写的集合执行此操作:
要成为类型协变,必须以严格的只读方式使用泛型参数;它只能从类型中写出,而不能读入(因此是关键字)。这就是
IEnumerable
示例有效,但List
示例无效的原因。顺便说一句,数组确实支持类型协变(我相信 Java 也支持),因此数组也可能出现同样类型的运行时错误。类型逆变意味着相反。为了支持类型逆变,泛型参数必须只能读入,而不能写出。这允许您替换不太具体的类型。
Action
是类型矛盾的一个示例:strAction
被声明为采用字符串参数,但如果您替换对象类型。将传入一个字符串,但如果设置为使用它的委托选择将其视为对象,那么就这样吧。没有造成任何伤害。为了完整起见,
Func
是Action
的逆情况;这里仅返回 T,因此它是协变的:myObjectFunc 被编码为返回一个对象。如果您将其设置为返回字符串的值,那么,同样不会造成任何损害。
Bottom Line: Resharper has investigated your type, and discovered that
TFrom
may be used contravariantly, andTTo
covariantly. Accepting the refactor would allow you to use these types with greater flexibility, as described below. If that might be of value to you, accept it.Note, however, that accepting this refactor would place restrictions on how you use these types in the future. If you ever write a method that takes
TTo
as a parameter, you'll get a compiler error, since coviariant types cannot be read in. And ditto forTFrom
: you'll never be able to have a method that returns this type, or has anout
parameter of this type.That's telling you that
TFrom
is contravariant, and thatTTo
is covariant. These were features recently added to C#Type covariance means that a more specific type may be passed in, while contravariance means that a less specific type may be passed in.
IEnumerable<T>
is a good example of type covariance. Since items in anIEnumerable<T>
are read only, you may set it to something more specific:Consider what could happen if (hypothetically) you were allowed to do this for collections that were read/write:
To be type covariant, a generic parameter must be used in a strictly read-only manner; it must only ever be written out from the type, and never read in (hence the keywords). That's why the
IEnumerable<T>
example works, but theList<T>
example doesn't. By the way, arrays do support type covariance (since Java does, I believe), and so this same kind of runtime error is possible with arrays.Type contravariance means the opposite. To support type contravariance a generic parameter must be read in only, and never written out. This allows you to substitute less specific types in.
Action<T>
is an example of type contravaince:strAction
is declared to take a string parameter, but it works fine if you substitute an object type. A string will be passed in, but if the delegate it's set to work with chooses to treat it as an object, then so be it. No harm done.For completeness,
Func<T>
is the inverse case ofAction<T>
; hereT
is only returned, therefore it's covariant:myObjectFunc
is coded to return an object. If you set it to something that returns a string, then, again, no harm done.作为此选择可能如何影响您的应用程序的示例,假设您有一个实现
IModelMapper
的类型CustomerAddressMapper
和另一个SupplierAddressMapper
实现IModelMapper
。Customer
和Supplier
类型共享一个基类Company
,但它们的地址逻辑不同,因此我们需要单独的类型来处理这个问题。现在假设您有一个采用
IMapper
的方法。在接口逆变之前,您无法将CustomerAddressMapper
或SupplierAddressMapper
的实例传递给此方法。现在,如果您在TFrom
类型参数上使用in
修饰符,则可以。此外,由于
TTo
参数的协变性,您还可以将CustomerAddressMapper
传递给需要IMapper
的方法。As an example of how this choice might affect your application, assume you have a type
CustomerAddressMapper
that implementsIModelMapper<Customer, Address[]>
and another oneSupplierAddressMapper
that implementsIModelMapper<Supplier, Address[]>
. TheCustomer
andSupplier
types share a base classCompany
, but their address logic is distinct, so we need separate types to handle this.Now assume that you have a method that takes an
IMapper<Company, Address[]>
. Before interface contravariance, you would not be able to pass instances ofCustomerAddressMapper
orSupplierAddressMapper
to this method. Now, if you use thein
modifier on theTFrom
type parameter, you can.Furthermore, because of covariance on the
TTo
parameter, you can also pass aCustomerAddressMapper
to methods that require anIMapper<Customer, object>
.