我在理解如何在现实世界中使用协方差和逆变时遇到了一些麻烦.
到目前为止,我见过的唯一例子是同样的旧数组示例.
object[] objectArray = new string[] { "string 1", "string 2" };
Run Code Online (Sandbox Code Playgroud)
很高兴看到一个允许我在开发过程中使用它的例子,如果我能看到它在其他地方使用的话.
在.NET中,引用类型数组是共变体.这被认为是一个错误.但是,我不明白为什么这么糟糕考虑以下代码:
string[] strings = new []{"Hey there"};
object[] objects = strings;
objects[0] = new object();
Run Code Online (Sandbox Code Playgroud)
哦,这个编译并在运行时失败.当我们试图将一个对象粘贴到一个字符串[]中时.好的,我同意臭,但是T []扩展了Array并且还实现了IList(并且IList<T>,我想知道它是否实现了IList<BaseType> ......>.Array和IList都允许我们犯同样的可怕错误.
string[] strings = new []{"Hey there"};
Array objects = strings;
objects.SetValue(new object(),new[]{0});
Run Code Online (Sandbox Code Playgroud)
IList版本
string[] strings = new []{"Hey there"};
IList objects = strings;
objects[0] = new object();
Run Code Online (Sandbox Code Playgroud)
T []类由CLR生成,并且必须包含对set_Item方法等效的类型检查(数组实际上没有一个).
是否担心设置为T []必须在运行时进行类型检查(这违反了编译时期望的类型安全性)?当有相同的方法通过上面提供的手段射击自己的脚时,为什么它被认为有害于阵列显示这种属性?
你觉得问题很奇怪吗?是的,发生的事也很奇怪.让我解释.
我从C#Arrays中找到了这个Covariance和Contravariance的片段
string[] strings = new string[1];
object[] objects = strings;
objects[0] = new object();
Run Code Online (Sandbox Code Playgroud)
Jon skeet解释说上面的代码会抛出ArrayTypeMismatchException,正如所说的那样.
我做的是我在第3行放置一个断点,使用DebuggerVisualizer我手动设置objects[0] = new object()它不会抛出任何错误,它的工作原理.稍后检查strings[0].GetType()返回System.Object.不仅System.Object可以通过上述过程在string []中设置任何类型.
我不知道这是怎么发生的我在那里提出我的问题作为评论在同一个问题我看到了这个但没有答案.
我很想知道背后发生了什么.有人解释一下.
在重现上述行为后试试这个
int len = strings[0].Length;
Run Code Online (Sandbox Code Playgroud)
如果你把鼠标放在属性长度上是strings[0].Length threw ArgumentException用消息说,Cannot find the method on the object instance但实际上它不会抛出异常和代码运行产生结果len=0
我得到了System.ArrayTypeMismatchException: Source array type cannot be assigned to destination array type此代码段的异常:
var uints = GetArray();
if (uints is int[])
{
var list = ((int[])uints).ToList(); // fails when call ToList()
}
private Array GetArray()
{
var result = new uint[] { uint.MaxValue, 2, 3, 4, 5 };
return result;
}
Run Code Online (Sandbox Code Playgroud)
然后我求助于Jon的回答为什么在C#中"int []是uint [] == true",它告诉我,由于GetArray()返回a Array,转换在运行时被推迟,而CLR允许这种转换int[] to uint[](vice versa).如果我在转换后检查值,它实际上工作正常:
foreach (var i in ((int[])units))
{
System.Console.WriteLine(i.GetType());
System.Console.WriteLine(i);
}
Run Code Online (Sandbox Code Playgroud)
我会得到:
System.Int32
-1
System.Int32 …Run Code Online (Sandbox Code Playgroud) 为什么整数数组不是对象数组?为什么“object[]”类型的模式不能用于“int[]”?
1 is object
True
new int[10] is object
True
new int[10] is object[] // Why?
False
(Array)new int[10] is object[]
False
(Array)new object[10] is object[]
True
new object() is object
True
new object[10] is object
True
new object[10] is object[]
True
int[] arr = new int[10];
// Why the compilation error?
// error CS8121: An expression of type 'int[]' cannot be handled by a pattern of type 'object[]'
if (arr is object[] objArr)
Console.WriteLine(objArr);
// And this works:
if …Run Code Online (Sandbox Code Playgroud)