1

(Even if you don't know about Autocad, you can help if you know about dynamic C# objects)

I'm trying to create an Autocad command, using .NET (C#), that allows the user to select entities, and from those entities, sum their lengths.

The selection part is fine, I was able to get a list of selected elements either as

  • AcadEntity; or
  • DBObject

But there are many subtypes of AcadEntity that have the length property. (Example: AcadLine, AcadLWPolyline, etc.) - I don't want to know in compile time what all those types are, and I can't trust regular Autocad users to use only one or two of those types.

So, I must check whether these objects contain the property "Length" and get that value.

Obviously I can do a 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) {  }

But as you know, creating tons of exceptions is really not the best way of programming things. So, I need a clean solution for that.


What have I tried?

  • Getting properties via reflection:

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

All of these always return "null"

Looking at the given objects, they're "System.__ComObject". The "Length" property, when available, appears in the debugger in the "Expand Dynamic View".

  • Getting the property value via string with this answer here, where someone can use RuntimeBinder to get a property via string... so I assume there might be a way to check if it exists before calling it, right?

This code works, but only if there is "Length". Is there a way to verify it before calling the last line?

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);

What do I think could be good solutions?

  • Enumerating a dynamic object's properties - I've found many questions about this, all of them using third party libraries, nothing simple at all (if the debugger can enumerate them, why can't I?)
  • Instancing or casting to an AcDbCurve object (if that exists in some library I may be missing). I've read this is a parent type to all curves (which I assume that contain "Length"). But there isn't an IAcadCurve or similar.
  • Casting dynamic objects to ExpandoObjects or something like finding an interface containing the members listed.

So far I found:

  • Third party libraries - Is that really necessary? Should this really be so complicated? - I'm not up to use/install them
  • One of the answers mentioned before, that get very close to it, but there is one step missing
Community
  • 1
  • 1
Daniel Möller
  • 84,878
  • 18
  • 192
  • 214
  • This article explains for to reflect a System.__ComObject. [Basic Instincts - Inspecting COM Objects with Reflection](https://msdn.microsoft.com/en-us/magazine/dd347981.aspx). – TnTinMn Mar 10 '17 at 18:09

0 Answers0