C# 无法将“System.Object[]”类型的对象强制转换为“MyObject[]”,这是怎么回事?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/212429/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 18:19:53  来源:igfitidea点击:

Unable to cast object of type 'System.Object[]' to 'MyObject[]', what gives?

c#.netarraysreflectioncasting

提问by Rob Stevenson-Leggett

Scenario:

设想:

I'm currently writing a layer to abstract 3 similar webservices into one useable class. Each webservice exposes a set of objects that share commonality. I have created a set of intermediary objects which exploit the commonality. However in my layer I need to convert between the web service objects and my objects.

我目前正在编写一个层,将 3 个类似的 Web 服务抽象为一个可用的类。每个 Web 服务都公开一组共享共性的对象。我创建了一组利用共性的中间对象。但是,在我的图层中,我需要在 Web 服务对象和我的对象之间进行转换。

I've used reflection to create the appropriate type at run time before I make the call to the web service like so:

在像这样调用 Web 服务之前,我已经使用反射在运行时创建了适当的类型:

    public static object[] CreateProperties(Type type, IProperty[] properties)
    {
        //Empty so return null
        if (properties==null || properties.Length == 0)
            return null;

        //Check the type is allowed
        CheckPropertyTypes("CreateProperties(Type,IProperty[])",type);

        //Convert the array of intermediary IProperty objects into
        // the passed service type e.g. Service1.Property
        object[] result = new object[properties.Length];
        for (int i = 0; i < properties.Length; i++)
        {
            IProperty fromProp = properties[i];
            object toProp = ReflectionUtility.CreateInstance(type, null);
            ServiceUtils.CopyProperties(fromProp, toProp);
            result[i] = toProp;
        }
        return result;
    }

Here's my calling code, from one of my service implementations:

这是我的调用代码,来自我的服务实现之一:

Property[] props = (Property[])ObjectFactory.CreateProperties(typeof(Property), properties);
_service.SetProperties(folderItem.Path, props);

So each service exposes a different "Property" object which I hide behind my own implementation of my IProperty interface.

因此,每个服务都公开了一个不同的“属性”对象,我将其隐藏在我自己的 IProperty 接口实现后面。

The reflection code works in unit tests producing an array of objects whose elements are of the appropriate type. But the calling code fails:

反射代码在单元测试中工作,生成元素为适当类型的对象数组。但调用代码失败:

System.InvalidCastException: Unable to cast object of type 'System.Object[]' to type 'MyProject.Property[]

System.InvalidCastException:无法将“System.Object[]”类型的对象转换为“MyProject.Property[]”

Any ideas?

有任何想法吗?

I was under the impression that any cast from Object will work as long as the contained object is convertable?

我的印象是,只要包含的对象是可转换的,来自 Object 的任何强制转换都可以工作?

采纳答案by Jon Skeet

Alternative answer: generics.

替代答案:泛型。

public static T[] CreateProperties<T>(IProperty[] properties)
    where T : class, new()
{
    //Empty so return null
    if (properties==null || properties.Length == 0)
        return null;

    //Check the type is allowed
    CheckPropertyTypes("CreateProperties(Type,IProperty[])",typeof(T));

    //Convert the array of intermediary IProperty objects into
    // the passed service type e.g. Service1.Property
    T[] result = new T[properties.Length];
    for (int i = 0; i < properties.Length; i++)
    {
        T[i] = new T();
        ServiceUtils.CopyProperties(properties[i], t[i]);
    }
    return result;
}

Then your calling code becomes:

然后您的调用代码变为:

Property[] props = ObjectFactory.CreateProperties<Property>(properties);
_service.SetProperties(folderItem.Path, props);

Much cleaner :)

干净多了:)

回答by Tom Ritter

You can't convert an array like that - it's returning an array of objects, which is different from an object. Try Array.ConvertAll

您不能像这样转换数组 - 它返回一个对象数组,这与对象不同。尝试Array.ConvertAll

回答by TheSmurf

That's correct, but that doesn't mean that you can cast containers of type Object to containers of other types. An Object[] is not the same thing as an Object (though you, strangely, could cast Object[] to Object).

这是正确的,但这并不意味着您可以将 Object 类型的容器转换为其他类型的容器。Object[] 与 Object 不同(尽管您很奇怪,可以将 Object[] 转换为 Object)。

回答by Marc Gravell

Basically, no. There are a few, limited, uses of array covariance, but it is better to simply know which type of array you want. There is a generic Array.ConvertAll that is easy enough (at least, it is easier with C# 3.0):

基本上,没有。数组协方差有一些有限的用途,但最好简单地知道您想要哪种类型的数组。有一个通用的 Array.ConvertAll 很容易(至少,使用 C# 3.0 更容易):

Property[] props = Array.ConvertAll(source, prop => (Property)prop);

The C# 2.0 version (identical in meaning) is much less eyeball-friendly:

C# 2.0 版本(含义相同)不太吸引眼球:

 Property[] props = Array.ConvertAll<object,Property>(
     source, delegate(object prop) { return (Property)prop; });

Or just create a new Property[] of the right size and copy manually (or via Array.Copy).

或者只是创建一个合适大小的新 Property[] 并手动复制(或通过Array.Copy)。

As an example of the things you cando with array covariance:

作为您可以使用数组协方差执行的操作的示例:

Property[] props = new Property[2];
props[0] = new Property();
props[1] = new Property();

object[] asObj = (object[])props;

Here, "asObj" is stilla Property[]- it it simply accessible as object[]. In C# 2.0 and above, generics usually make a better option than array covariance.

在这里,“asObj”仍然是一个Property[]- 它可以简单地作为object[]. 在 C# 2.0 及更高版本中,泛型通常是比数组协方差更好的选择。

回答by Jon Skeet

As others have said, the array has to be of the right type to start with. The other answers have shown how to convert a genuine object[] after the fact, but you can create the right kind of array to start with using Array.CreateInstance:

正如其他人所说,数组必须是正确的类型才能开始。其他答案已经展示了如何在事后转换真正的 object[],但您可以创建正确类型的数组,以使用Array.CreateInstance开始:

object[] result = (object[]) Array.CreateInstance(type, properties.Length);

Assuming typeis a reference type, this should work - the array will be of the correct type, but you'll use it as an object[]just to populate it.

假设type是引用类型,这应该可以工作 - 数组将是正确的类型,但您将使用它作为object[]填充它。

回答by Mr. Graves

in C# 2.0 you cando this using reflection, without using generics and without knowing the desired type at compile time.

在 C# 2.0 中,您可以使用反射做到这一点,而无需使用泛型,也无需在编译时知道所需的类型。

//get the data from the object factory
object[] newDataArray = AppObjectFactory.BuildInstances(Type.GetType("OutputData"));
if (newDataArray != null)
{
    SomeComplexObject result = new SomeComplexObject();
    //find the source
    Type resultTypeRef = result.GetType();
    //get a reference to the property
    PropertyInfo pi = resultTypeRef.GetProperty("TargetPropertyName");
    if (pi != null)
    {
        //create an array of the correct type with the correct number of items
        pi.SetValue(result, Array.CreateInstance(Type.GetType("OutputData"), newDataArray.Length), null);
        //copy the data and leverage Array.Copy's built in type casting
        Array.Copy(newDataArray, pi.GetValue(result, null) as Array, newDataArray.Length);
    }
}

You would want to replace all the Type.GetType("OutputData") calls and the GetProperty("PropertyName") with some code that reads from a config file.

您可能希望用一些从配置文件中读取的代码替换所有 Type.GetType("OutputData") 调用和 GetProperty("PropertyName")。

I would also use a generic to dictate the creation of SomeComplexObject

我还将使用泛型来指示 SomeComplexObject 的创建

T result = new T();
Type resultTypeRef = result.GetType();

But I said you didn't need to use generics.

但我说你不需要使用泛型。

No guarantees on performance/efficiency, but it does work.

不保证性能/效率,但它确实有效。