情景:
我正在编写一个图层,将3个类似的Web服务抽象为一个可用的类。每个Web服务都公开一组共享共性的对象。我创建了一组利用共性的中间对象。但是在我的图层中,我需要在Web服务对象和我的对象之间进行转换。
在我调用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;
}
这是我的调用代码,来自我的一个服务实现:
Property[] props = (Property[])ObjectFactory.CreateProperties(typeof(Property), properties);
_service.SetProperties(folderItem.Path, props);
因此,每个服务都会公开一个不同的“Property”对象,我将其隐藏在我自己的IProperty接口实现之后。
反射代码在单元测试中起作用,产生一个对象数组,其元素的类型是合适的。但是调用代码失败了:
System.InvalidCastException:无法执行 'System.Object []'类型的强制转换对象 输入 “MyProject.Property []
有什么想法吗?
我的印象是,只要包含的对象可以转换,来自Object的任何强制转换都会起作用吗?
答案 0 :(得分:9)
基本上没有。数组协方差有一些有限的用法,但最好只知道你想要哪种类型的数组。有一个通用的Array.ConvertAll很容易(至少,使用C#3.0更容易):
Property[] props = Array.ConvertAll(source, prop => (Property)prop);
C#2.0版本(意思相同)对眼球友好程度要低得多:
Property[] props = Array.ConvertAll<object,Property>(
source, delegate(object prop) { return (Property)prop; });
或者只是创建一个合适大小的新Property []并手动复制(或通过Array.Copy
)。
作为 可以用数组协方差做的事情的一个例子:
Property[] props = new Property[2];
props[0] = new Property();
props[1] = new Property();
object[] asObj = (object[])props;
此处,“asObj”仍然一个Property[]
- 它只能作为object[]
访问。在C#2.0及更高版本中,泛型通常比数组协方差更好。
答案 1 :(得分:9)
替代答案:泛型。
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;
}
然后你的主叫代码变成:
Property[] props = ObjectFactory.CreateProperties<Property>(properties);
_service.SetProperties(folderItem.Path, props);
更清洁:)
答案 2 :(得分:5)
正如其他人所说,数组必须是正确的类型。其他答案已经展示了如何在事实之后转换真实对象[],但是您可以创建正确类型的数组以开始使用Array.CreateInstance:
object[] result = (object[]) Array.CreateInstance(type, properties.Length);
假设type
是引用类型,这应该有效 - 数组的类型正确,但您只需将其用作object[]
来填充它。
答案 3 :(得分:4)
你不能像这样转换一个数组 - 它返回一个对象数组,它与一个对象不同。试试Array.ConvertAll
答案 4 :(得分:1)
这是正确的,但这并不意味着您可以将Object类型的容器转换为其他类型的容器。 Object []与Object不同(尽管奇怪的是,你可以将Object []转换为Object)。
答案 5 :(得分:1)
在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);
}
}
您希望将所有Type.GetType(“OutputData”)调用和GetProperty(“PropertyName”)替换为从配置文件中读取的一些代码。
我还会使用泛型来指定SomeComplexObject的创建
T result = new T();
Type resultTypeRef = result.GetType();
但我说你不需要使用泛型。
不保证性能/效率,但确实有效。