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

前端 未结 6 1832
忘掉有多难
忘掉有多难 2021-02-19 18:09

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 hav

相关标签:
6条回答
  • 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):

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

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

     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).

    As an example of the things you can do with array covariance:

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

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

    0 讨论(0)
  • 2021-02-19 18:35

    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[] result = (object[]) Array.CreateInstance(type, properties.Length);
    

    Assuming type is 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.

    0 讨论(0)
  • 2021-02-19 18:35

    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).

    0 讨论(0)
  • 2021-02-19 18:37

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

    //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.

    I would also use a generic to dictate the creation of 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.

    0 讨论(0)
  • 2021-02-19 18:44

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

    0 讨论(0)
  • 2021-02-19 18:46

    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 :)

    0 讨论(0)
提交回复
热议问题