1

(即使您不了解 Autocad,如果您了解动态 C# 对象,也可以提供帮助)

我正在尝试使用 .NET (C#) 创建一个 Autocad 命令,该命令允许用户选择实体,并从这些实体中对它们的长度求和。

选择部分很好,我可以得到一个选定元素的列表

  • 学院实体;或者
  • 数据库对象

但是 AcadEntity 的许多子类型都具有长度属性。(例如:AcadLine、AcadLWPolyline 等) - 我不想在编译时知道所有这些类型是什么,而且我不能相信普通的 Autocad 用户只使用其中一种或两种类型。

因此,我必须检查这些对象是否包含属性“长度”并获取该值。

显然我可以做一个try-catch:

dynamic dynaEntity = (dynamic)AcadEntityInstance
try
{
   double len = dynaEntity.Length;
   LengthsPerType.AddOrSum(entityType, len);//personal method, no problem here

   //entityType is a string found in AcadEntityInstance.ObjectName
   //it returns an "AcDbLine", for instance, which is not an actual System.Type. 
   //The related Type is "AcadLine" - I can, for instance do (AcadLine)AcadEntityInstance
}
catch (System.Exception E) {  }

但是如您所知,创建大量异常并不是最好的编程方式。所以,我需要一个干净的解决方案。


我尝试了什么?

  • 通过反射获取属性:

    PropertyInfo prop = dynaEntity.GetType().GetProperty("Length");
    PropertyInfo prop = AcadEntityInstance.GetType().GetProperty("Length");
    PropertyInfo prop = ((object)AcadEntityInstance).GetType().GetProperty("Length");
    

所有这些总是返回“null”

查看给定的对象,它们是“System.__ComObject”。“长度”属性(如果可用)出现在“扩展动态视图”的调试器中。

  • 使用此答案通过字符串获取属性值在这里,有人可以使用 RuntimeBinder 通过字符串获取属性...所以我认为可能有一种方法可以在调用它之前检查它是否存在,对吧?

此代码有效,但前提是存在“长度”。在调用最后一行之前有没有办法验证它?

var ArgInfo = Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0, null);
var getMember = Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, "Length", dynaEntity.GetType(), new[] { ArgInfo });
var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(getMember);
var result = site.Target(site, dynaEntity);

我认为什么是好的解决方案?

  • 枚举动态对象的属性——我发现了很多关于这个的问题,它们都使用第三方库,一点都不简单(如果调试器可以枚举它们,为什么我不能?)
  • 实例化或转换为 AcDbCurve 对象(如果该对象存在于某些库中,我可能会丢失)。我读过这是所有曲线的父类型(我假设它包含“长度”)。但是没有 IAcadCurve 或类似的。
  • 将动态对象转换为 ExpandoObjects 或类似查找包含列出的成员的接口。

到目前为止,我发现:

  • 第三方库——真的有必要吗?这真的应该这么复杂吗?- 我不会使用/安装它们
  • 前面提到的答案之一,非常接近它,但是缺少一步
4

0 回答 0