So what is different between <T> and <in T>?
Sự khác biệt là in T
cho phép bạn chuyển loại chung hơn (ít bắt nguồn) hơn loại được chỉ định.
And what is the purpose of contravariant here?
ReSharper gợi ý để sử dụng contravariance ở đây vì nó nhìn thấy bạn đang đi qua các tham số T
vào phương pháp Validate
và muốn để cho phép bạn mở rộng các loại đầu vào bằng cách làm cho nó ít generic.
Nói chung, nghịch lý được giải thích theo chiều dài trong Contravariance explained và trong Covariance and contravariance real world example và tất nhiên trong suốt tài liệu trên MSDN (có great FAQ by the C# team).
Có một ví dụ tốt đẹp thông qua MSDN:
abstract class Shape
{
public virtual double Area { get { return 0; }}
}
class Circle : Shape
{
private double r;
public Circle(double radius) { r = radius; }
public double Radius { get { return r; }}
public override double Area { get { return Math.PI * r * r; }}
}
class ShapeAreaComparer : System.Collections.Generic.IComparer<Shape>
{
int IComparer<Shape>.Compare(Shape a, Shape b)
{
if (a == null) return b == null ? 0 : -1;
return b == null ? 1 : a.Area.CompareTo(b.Area);
}
}
class Program
{
static void Main()
{
// You can pass ShapeAreaComparer, which implements IComparer<Shape>,
// even though the constructor for SortedSet<Circle> expects
// IComparer<Circle>, because type parameter T of IComparer<T> is
// contravariant.
SortedSet<Circle> circlesByArea =
new SortedSet<Circle>(new ShapeAreaComparer())
{ new Circle(7.2), new Circle(100), null, new Circle(.01) };
foreach (Circle c in circlesByArea)
{
Console.WriteLine(c == null ? "null" : "Circle with area " + c.Area);
}
}
}
How can I apply the usage of contravariant in this example?
Hãy nói rằng chúng tôi có tổ chức của chúng tôi:
public class Entity : IEntity
{
public string Name { get; set; }
}
public class User : Entity
{
public string Password { get; set; }
}
Chúng tôi cũng có một giao diện IBusinessManager
và thực hiện BusinessManager
, mà chấp nhận một IBusinessValidator
:
public interface IBusinessManager<T>
{
void ManagerStuff(T entityToManage);
}
public class BusinessManager<T> : IBusinessManager<T> where T : IEntity
{
private readonly IBusinessValidator<T> validator;
public BusinessManager(IBusinessValidator<T> validator)
{
this.validator = validator;
}
public void ManagerStuff(T entityToManage)
{
// stuff.
}
}
Bây giờ, cho phép nói rằng chúng ta đã tạo ra một validator chung cho bất kỳ IEntity
:
public class BusinessValidator<T> : IBusinessValidator<T> where T : IEntity
{
public void Validate(T entity)
{
if (string.IsNullOrWhiteSpace(entity.Name))
throw new ArgumentNullException(entity.Name);
}
}
Và bây giờ, chúng tôi muốn vượt qua BusinessManager<User>
và IBusinessValidator<T>
. Bởi vì nó là contravariant, tôi có thể vượt qua nó BusinessValidator<Entity>
.
Nếu chúng ta loại bỏ các từ khóa in
, chúng tôi nhận được lỗi sau:
Nếu chúng tôi bao gồm nó, điều này biên dịch tốt.
Bạn đã đọc tài liệu chưa? https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx –
Có, tôi đã đọc nó. Tuy nhiên tôi có một vấn đề nhỏ với sự hiểu biết bài báo. Dù sao, liên kết đã giúp. –