Ok so I stumbled on to this subject the other day and thought it was worth noting. Take these simple classes:
public class First
{
public String FirstOutput { get; set; }
}
public class Second : First
{
public String SecondOutput { get; set; }
}
public class Third : Second
{
public String ThirdOutput { get; set; }
}
So from this you can see that
Third inherits
Second which in turns inherits
First. By terminology this would mean that
Third is "smaller" than
Second and
First is "larger" than both. Here's an example of Covariance:
public class Covariance
{
public Covariance()
{
Func<First> returnFirstFunc = ReturnFirst;
//This works since the Func has a return type of First
Func<Second> returnSecondFunc = ReturnThird;
Second secondTest = returnSecondFunc();
secondTest.FirstOutput = "First";
secondTest.SecondOutput = "First";
//This works since the Func has a return type of Third which is smaller
//that Second. Therefore anyone using this Func will expect a Second to
//be returned and will only use the methods/properties that a Second object
//would have. Methods/Properties that Third has by inheritance.
Func<Third> returnThirdFunc = ReturnSecond;
//THIS WILL NOT WORK
//Due to Covariance, the return of the method must be equal or smaller
//that the expected type. returnThirdFunc expects a Third or smaller object
//but the ReturnSecond method returns a Second which is not smaller than Third.
//Afterall, Third : Second
//
//Third thirdTest = returnThirdFunc();
//Is the same as:
//Third thirdTest = new Second();
}
private First ReturnFirst()
{
return new First();
}
private Second ReturnSecond()
{
return new Second();
}
private Third ReturnThird()
{
return new Third();
}
}
Basically what this all means is that with return types, the return type must be smaller or equal to the field it's being set to. When you are dealing with Funcs, the return type must be smaller or equal to the return type for the method it's being set it. Why is that? Well think of it like this:
It's your first day on the job and some guy tells you to write something with whatever returnFirstFunc() returns. Now you have no way to look at the code, so you can only know that it returns
First. For all you know, it could return
First,
Second, or
Third. So you would do this:
First someFirst;
someFirst = returnFirstFunc(); //Could return anything smaller than First
someFirst.FirstOutput; //Completely legal and safe
But would you do this?
someFirst.ThirdOutput;
Of course not since you only can assume it is a
First. Now let's do this in reverse. Say from the above example you were allowed to do this:
Func<Third> returnThirdFunc = ReturnSecond;
Could you do this?
Third third;
third = returnThirdFunc();
third.ThirdOutput;
Yeah you can't since the
Second type doesn't have the ThirdOutput property.
In short Covariance is the allowance of Smaller types or equal. If a method returns back Third, then you can use that method for anything that is
Third or Smaller (
Second,
First,
Object) but not for something Larger (
Fourth,
Fifth, ect).
No comments:
Post a Comment