首页 > 解决方案 > 代码在监视窗口中工作,但在代码执行期间无法转换对象

问题描述

我的.NET 4.7.2服务器应用程序中有这些代码行:

object saveObject = proxyDef.GetEntityAsNativeObject(entity, DynamicProxyAssembly); // this works
((AxdSalesOrder)saveObject).SalesTable[0].TableDlvAddr = null; // this throws error

我可以在中执行空集(上面的第 2 行),VS2019 Watch Window它可以完美地工作并达到预期的效果。但是当我允许它在正常执行中运行时(无论是否在调试模式下),我在第二行得到一个未处理的异常:

无法将“AxdSalesOrder”类型的对象转换为“Elogix.MSAx.Core.Ax2012ElogixServices.AxdSalesOrder”类型

有与该类型相关的动态内容:

public override object GetEntityAsNativeObject(MSAxEntity entity, Assembly dynamicProxyAssembly) {
  var salesOrderObject = Activator.CreateInstance(dynamicProxyAssembly.GetType("AxdSalesOrder"));

  var salesOrderTable = DynamicEntityUtil.CreateObjectFromDynamicEntity(entity, dynamicProxyAssembly, "AxdEntity_SalesTable");

  Array tableLines =
    Array.CreateInstance(
      salesOrderObject.GetType().GetProperty("SalesTable").PropertyType.GetElementType(), 1);

  tableLines.SetValue(salesOrderTable, 0);
  salesOrderObject.SetPropertyValue("SalesTable", tableLines);
  return salesOrderObject;
}

public static object CreateObjectFromDynamicEntity(DynamicEntity entity, Assembly dynamicProxyAssembly, string objectTypeName) {
  return CreateObjectFromDynamicEntity(entity, dynamicProxyAssembly.GetType(objectTypeName));
}

public static object CreateObjectFromDynamicEntity(DynamicEntity entity, Type type) {
  if (type == null) {
    throw new ArgumentException("Cannot create object from dynamic entity because \"Type\" is null.");
  }

  if (type.IsArray) {
    return CreateArrayFromDynamicEntity(entity, type);
  }

  return CreateClassFromDynamicEntity(entity, type);
}

private static object CreateClassFromDynamicEntity(DynamicEntity entity, Type type) {
  var nativeObject = Activator.CreateInstance(type);

  // this will recursively convert the dynamic values to the native type values on the object.
  updateValuesFromDynamicValues(entity);

  var modifiedProperties = from property in entity.Properties
  //where property.State != DynamicPropertyState.Unchanged
  select property;

  foreach(var property in modifiedProperties) {
    Type valueUnderlyingType = Nullable.GetUnderlyingType(property.Type);
    if (valueUnderlyingType != null && valueUnderlyingType.IsEnum) {
      PropertyInfo info = nativeObject.GetType().GetProperty(property.Name);
      Type targetUnderlyingType = Nullable.GetUnderlyingType(info.PropertyType);

      if (property.Value == null) {
        info.SetValue(nativeObject, null, null);
      } else {
        object correctedValue = property.Value.CorrectedEnumValue(targetUnderlyingType);
        info.SetValue(nativeObject, correctedValue, null);
      }
    } else if (property.Type.IsEnum) {
      if (property.Value == null) {
        continue;
      }
      object correctedValue = property.Value.CorrectedEnumValue(property.Type);
      nativeObject.SetPropertyValue(property.Name, correctedValue);
    } else {
      try {
        nativeObject.SetPropertyValue(property.Name, property.Value);
      } catch (Exception ex) {
        Log.Write(ex.Message);
      }
    }
  }

  return nativeObject;
}

这是它在 VS2019 中的外观Watch Window

在此处输入图像描述

这样做Immediate Window

var t = saveObject.GetType();
t.FullName
"AxdSalesOrder"

正如你所看到的,由于类型的FullName动态特性,类型不是很完整,没有任何限制。

我可以这样尝试:

(saveObject as AxdSalesOrder).SalesTable[0].TableDlvAddr = null;

同样,这在 Watch 中有效,但在正常执行时抛出此异常:

你调用的对象是空的。

显然,VS/Watch知道 type,这就是为什么它可以在 Watch 内部执行而不会出错。但是.net 运行时显然不知道运行时的类型。我怎样才能让这个对象在正常的代码执行中像在 Watch 中运行一样工作?

标签: c#.netinheritance

解决方案


这里的答案是利用动态类型,因为这里没有静态类型:

dynamic saveObject = proxyDef.GetEntityAsNativeObject(entity, DynamicProxyAssembly); 
saveObject.SalesTable[0].TableDlvAddr = null; 

另一种可能的方法是使用反射,但是由于应用于对象的表达式涉及两个属性和一个索引查找 ( .SalesTable[0].TableDlvAddr),这看起来可读性要差得多。

GetEntityAsNativeObject也可以从这种风格中受益,您可以考虑将其重写为使用动态绑定而不是反射。


推荐阅读