我有一个“对象”类型的字段。当我在 Visual Studio 的 Watch 窗口中检查它时,我看到了它的 Object[],当我钻入元素时,我看到每个元素都是一个字符串。
但是,当我尝试将其转换为 String[] 时,我收到此错误:
无法将“MyObject”(其实际类型为“object[]”)转换为“string[]”string[]
为什么我不能做这个演员?将此对象转换为字符串数组的最佳方法是什么?
这是 C# 的一个特别令人困惑的特性。这是交易。
在整个讨论中,我们假设数组的元素类型是引用类型,而不是值类型。
C# 支持不安全的数组协方差。这意味着如果您有一个字符串数组,您可以将其转换为对象数组,因为字符串可以转换为对象:
string[] a1 = { "hello", "goodbye" };
object[] a2 = a1; // Legal
如果您然后尝试从 a2 中获取一个元素,它会起作用:
object o3 = a2[0];
这是合法的,因为a2[0]
is really a1[0]
,它是一个字符串,可以转换为对象。
但是,如果您尝试写入数组,那么您将在运行时收到错误消息:
a2[0] = new object();
这在运行时会失败,因为a2
它实际上是一个字符串数组,并且您不能将非字符串放入字符串数组中。
所以 C# 已经被严重破坏了;可以编写一个编译并看起来正常但在运行时突然崩溃并出现类型异常的程序,因为您试图将一个对象放入一个实际上不是对象数组的对象数组中。
你想要的功能比这更糟糕,谢天谢地 C# 不支持它。您想要的功能是:
object[] a4 = { "Hello" };
string[] a5 = a4;
那将是不安全的数组逆变。它像这样可怕地破裂:
a4[0] = new Customer(); // Perfectly legal
string s6 = a5[0];
现在我们只是将一个Customer复制到一个string类型的变量中。
您应该避免任何类型的数组协变或逆变;正如您所发现的,数组逆变是不合法的,并且数组协方差在您的程序中制造了一些意外爆炸的定时炸弹。使您的数组具有正确的类型。
string[] newarr = Array.ConvertAll(objects, s => (string)s);
- 编辑 -
既然你说我有一个object
(知道它object[]
实际上是一个)
string[] newarr = Array.ConvertAll((object[])objects, s => (string)s);
object[] original = new object[]{"1", "2"};
//some code in between here
object obj = original ;
object[] objArray = (object[])obj;
string[] newArray = new string[objArray.Length];
for(int i = 0; i < newArray; i++)
{
newArray[i] = (string)objArray[i];
}
这里的其他答案向您展示了更快/更短的转换方式。我把整件事写成这样,因为它显示了真正发生的事情和需要发生的事情。您应该在实际生产代码中使用一种更简单的方法。
面向对象编程的规则是——
“派生类始终可以类型转换为基类”并且“只有当基类推迟的当前实例实际上是派生类时,才能将基类转换为派生类”
例如(A 是基础,B 是派生的)
A a = new B(); // legal;
B b = (B) a ; // legal as "a" is actually B (in first statement)
非法:>
A a = new A();
B b = (B) a; // not legal as "a" is A only.
同样的事情也适用于 Object 和 String 类。对象是基类,字符串是派生类。
您应该转换集合中的每个元素,而不是集合本身。
object[] ovalues = new object[] { "alpha", "beta" };
string[] svalues = ovalues.Cast<string>().ToArray();