(即使您不了解 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 或类似查找包含列出的成员的接口。
到目前为止,我发现:
- 第三方库——真的有必要吗?这真的应该这么复杂吗?- 我不会使用/安装它们
- 前面提到的答案之一,非常接近它,但是缺少一步