类型参数和转换
C#的转化操作符支持下列转换:
- 数值转换
- 引用转换
- 装箱拆箱转换
- 自定义转换
决定采用的是哪种转换,发生在编译时,根据已知类型的操作数来决定。
泛型在编译的时候,还不知道具体类型是什么,运行时才知道
类型参数和转换
StringBUilder Foo<T> (T arg)
{
if(arg is StringBuilder)
{
return (StringBuilder)arg;//无法编译,原因是泛型T编译的时候还不知道类型
}
...
}
解决方案 1:
StringBuilder Foo<T>(T arg)
{
StringBuilder sb=arg as StringBuilder;
if(sb!=null) return sb;
...
}
解决方案 2:
return (StringBuilder)(Object)arg;
协变,逆变,不变
协变:当值作为返回值 out输出
逆变:当值作为输入input
不变:当值既输入又输出
public interface IEnumerable<out T> //协变,作为返回值输出
public delegate void Action<in T> //逆变,作为输入
public interface IList<T>
variance
协变、逆变、不变都叫做variance,variance 只能出现在接口和委托里
variance转换
1 variance转换是 引用转换 的一个例子。引用转换是指,无法改变底层的值,只能改变编译时的类型。
2 identity conversion 对于CLR而言从一个类型转化到相同的类型
合理的转换
如果从A到B的转换是本体转换或者隐式引用转换,
那么从IEnumerable<A> 到IEnumerable<B>的转换就是合理的,如:
IEnumerable<string> to IEnumerable<object>
IEnumerable<string> to IEnumerable<IConvertible>
IEnumerable<IDisposable> to IEnumerable<object>
不合理的转换
IEnumerable<object> to IEnumerable<string>
IEnumerable<string> to IEnumerable<Stream>
IEnumerable<int> to IEnumerable<Iconvertible>
IEnumerable<int> to IEnumerable<long>
案例
//引例,转换异常
IList<string> strings1 = new List<string> { "a", "b", "c" };
IList<object> objects1 = strings1;//这里会报错,这种转换不安全
//如果不报错的话,object1可以添加了一个object,
//那么strings1就可以访问到这个新添加的元素,但是新添加的元素并不是string,是一个object
objects1.Add(new object());
var newValue = strings1[3];
//协变(小变大)
//IEnumerable out关键字修饰,只能作为输出
//协变:IEnumerable<string> 可以转化为 IEnumerable<object>,子类的T可以转化为父类的
IEnumerable<string> strings = new List<string> { "a", "b", "c" };
IEnumerable<object> objects = strings;//合法的
//逆变(大变小,本质上还是小变大)
//逆变 Action<object>可以转化为Action<string> 即大变小
//本质上还是子类转化为父类,调用时传递参数将子类参数传递给父类参数
Action<object> objectAction =obj => Console.WriteLine(obj);
Action<string> stringAction = objectAction;//方法是object类型,传进去string是可以的
stringAction("print me");
//案例
IEnumerable<string> strings2 = new[] { "av", "b", "csadf", "d" };
//不合法 将IEnumerable<string>转化成 List<string>是不合法的,原因是List<T>是不变的
List<object> list = strings2
.Where(x => x.Length > 1)
.ToList();
//合法
List<object> list1 = strings2.Where(x => x.Length > 1)
.Cast<object>()
.ToList();
//合法
List<object> list2 = strings2.Where(x => x.Length > 1)
.ToList<object>();//发生了协变 从IEnurable<string>转化成了IEnurable<object>