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
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.
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.
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).
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.
You can't convert an array like that - it's returning an array of objects, which is different from an object. Try Array.ConvertAll
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 :)