Deriving Class from DesignScriptClass (C#)

This is my first time using the Autodesk.DesignScript package. I figured I would be able to either subclass from Point or create my own class which implements IPoint (I couldn’t find an interface for Point)

I expect this to be something simple…

Basically all I want is:

public class CustomPoint : Point
{
    public string Name { get; set; }

    public static CreateCustomPoint(double x, double y, double z, string name)
    {
        CustomPoint myPoint = CustomPoint.ByCoordinates(x, y, z);
        myPoint.Name = name;
        return myPoint;
    }
}

However, I get the error “Point does not contain a constructor that takes 0 arguments”.

Look into GitHub samples for a Better explanation but, Dynamo doesn’t have the “new” keyword, so you have to create your own private constructor CustomPoint() and a static method as constructor, something like “ByCoordinatesAndName”. This one can call the private one.
I suggest you also to put default values as much as possible.

Thanks Fabio, do you have a link to the GitHub samples?

In the above example my CreateCustomPoint is my static method for constructing the object, correct?

If I add a private constructor like:

private CustomPoint() {    }

I still get the error “Point does not contain a constructor that takes 0 arguments” as this is still trying to call a parameterless constructor on base which does not exist.

I’m on phone right now, gimme 1 hour and I give.you all the needed :slightly_smiling_face:

1 Like

it should like this

public class CustomPoint : Point
{
    public string Name { get; set; }
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }
    
    // default constructor (not shown as node)
    private CustomPoint() { }
    
    // node constructor
    public static CustomPoint ByCoordsAndName(double x = 0, double y = 0, double z 0 0, string name = "defaultName" )
    {
        CustomPoint myPoint = new CustomPoint();
        myPoint.X = x;
        myPoint.Y = y;
        myPoint.Z = z;
        myPoint.Name = name;
        return myPoint;
    }
}

hmmm, that’s exactly what I have…

You’re deriving from the Point in the Autodesk.DesignScript.Geometry namespace correct?

I haven’t implement properties for X, Y, Z as that should be implemented on the base class Point, correct?

I added your sample code and still get the same error:
image

EDIT: I don’t think it should matter but I’m targeting .NetStandard

He’s tolding you that Point doesn’t have that constructor, not your CustomPoint. Probabily it is a x=0, y=0, z=0 constructor.
Take a look at the next method “ByCoordsAndName”: your static constructor should like this in order to have a node “+” working correctly.

Try hit F12 on the Point class, it should display you the original class definition

Yep, the Point class definition contains no constructors, the Geometry class from which it derives also no constructors.

The base class DesignScriptEntity appears to have a constructor, but takes 0 arguments… I haven’t seen the “~” in code before.

image

I’ve tried and you’re right:

I suggest to avoid derive the class, it works fine, just make your point as a property :wink:

Yer only problem with this is I can’t for example “translate” my object using the built in Geomerty functions. I would have to use composition, unpack the property referencing a DesignScript.Geometry type, and then I think I would have to re-set the Pt property after any manipulation to the Point.

Again new to DesignScript so unsure if the translate would update my point object, or if it returns an new instance.

Also another issue is my CustomPoint can’t be displayed without getting the Pt property.

This is an example to create a Custom object (a Corridor object):

using acAppServ = Autodesk.AutoCAD.ApplicationServices;
using acDbServ = Autodesk.AutoCAD.DatabaseServices;
using acGeom = Autodesk.AutoCAD.Geometry;
using cdDbServ = Autodesk.Civil.DatabaseServices;
using cdAppServ = Autodesk.Civil.ApplicationServices;
using dynAppServ = Autodesk.AutoCAD.DynamoApp.Services;
using dynACNodes = Autodesk.AutoCAD.DynamoNodes;
using dynCDNodes = Autodesk.Civil.DynamoNodes;
using System;
using System.Collections.Generic;
using Autodesk.DesignScript.Runtime;
using DynamoObject = Autodesk.AutoCAD.DynamoNodes.ObjectBase;
using System.Linq;


namespace Civil3D.Geometry
{

    /// <summary>
    /// Dynamo Corridor object
    /// </summary>
    [DynamoServices.RegisterForTrace]
    public class CustomCorridor : DynamoObject
    {


        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Properties
        internal cdDbServ.Corridor m_Corridor = null; // The Civil 3D object.


        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constructor
        internal CustomCorridor(cdDbServ.Corridor corridor, bool isDynamoOwned) : base(corridor, isDynamoOwned) => this.m_Corridor = corridor;


        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Functions
        /// <summary>
        /// Returns Handle
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Query")]
        public string AutoCADHandle() => m_Corridor.Handle.ToString();


        /// <summary>
        /// Returns object
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Query")]
        public dynACNodes.Object AutoCADObject() => dynACNodes.Object.InternalMakeObject(m_Corridor, false);


        /// <summary>
        /// Returns the Core object that is compatible with the Corridor object of the core nodes
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Actions")]
        public dynCDNodes.Corridor CoreObject() => dynCDNodes.Selection.CorridorByName(m_Corridor.Name, dynACNodes.Document.Current);


        /// <summary>
        /// Returns the CodeSet Style name of the Corridor
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Query")]
        public string CodeSetStyleName() => m_Corridor.CodeSetStyleName;


        /// <summary>
        /// Returns the description of the Corridor
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Query")]
        public string Description() => m_Corridor.Description;


        /// <summary>
        /// Returns the Link Codes of the Corridor
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Actions")]
        public IList<string> LinkCodes() => m_Corridor.GetLinkCodes().ToList();


        /// <summary>
        /// Returns the name of the Corridor
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Query")]
        public string Name() => m_Corridor.Name;


        /// <summary>
        /// Returns the Point Codes of the Corridor
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Actions")]
        public IList<string> PointCodes() => m_Corridor.GetPointCodes().ToList();


        /// <summary>
        /// Returns the Shape Codes of the Corridor
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Actions")]
        public IList<string> ShapeCodes() => m_Corridor.GetShapeCodes().ToList();


        /// <summary>
        /// Returns the style of the Corridor
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Query")]
        public string Style() => m_Corridor.StyleName.ToString();


        /// <summary>
        /// Returns the TinSurfaces of the Corridor
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Query")]
        public IList<CustomTinSurface> Surfaces()
        {

            IList<CustomTinSurface> returnValue = new List<CustomTinSurface>();

            dynACNodes.Document document = dynACNodes.Document.Current;
            if (document == null) { throw new Exception("Current document is null."); }

            using (dynAppServ.DocumentContext ctx = new dynAppServ.DocumentContext(document.AcDocument))
            {
                acDbServ.Transaction tr = ctx.Transaction; 

                foreach (cdDbServ.CorridorSurface cdrsurf in m_Corridor.CorridorSurfaces)
                {
                    cdDbServ.TinSurface surface = tr.GetObject(cdrsurf.SurfaceId, acDbServ.OpenMode.ForRead) as cdDbServ.TinSurface;
                    if (surface != null) { returnValue.Add(new CustomTinSurface(surface, false)); }
                }
            }

            return returnValue;
        }



        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Override functions
        public override string ToString() => string.Format($"Corridor '{Name()}'");


        // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Static Functions
        /// <summary>
        /// Returns an Corridor by name
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Actions")]
        public static CustomCorridor GetCorridorByName(string name)
        {
            foreach (CustomCorridor corridor in GetCorridors())
            {
                if (corridor.m_Corridor.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase) == true) { return corridor; }
            }

            return null;
        }


        /// <summary>
        /// Returns a list of Corridors
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Actions")]
        public static IList<CustomCorridor> GetCorridors()
        {
            IList<CustomCorridor> returnValue = new List<CustomCorridor>();

            dynACNodes.Document document = dynACNodes.Document.Current;
            if (document == null) { throw new Exception("Current document is null."); }

            using (dynAppServ.DocumentContext ctx = new dynAppServ.DocumentContext(document.AcDocument))
            {
                acDbServ.Transaction tr = ctx.Transaction; 

                cdAppServ.CivilDocument civilDoc = cdAppServ.CivilDocument.GetCivilDocument(ctx.Database);

                foreach (acDbServ.ObjectId id in civilDoc.CorridorCollection)
                {
                    if (AutoCAD.Functions.IsObjectIdValid(id) == true)
                    {
                        cdDbServ.Corridor cdr = tr.GetObject(id, acDbServ.OpenMode.ForRead) as cdDbServ.Corridor;
                        if (cdr != null) { returnValue.Add(new CustomCorridor(cdr, false)); }
                    }
                }
            }

            return returnValue;
        }


        /// <summary>
        /// Get Corridor from object (i.e. selected object)
        /// </summary>
        [Dynamo.Graph.Nodes.NodeCategory("Actions")]
        public static CustomCorridor GetFromObject(dynACNodes.Object @object)
        {
            dynACNodes.Document document = dynACNodes.Document.Current;
            if (document == null) { throw new Exception("Current document is null."); }

            try
            {
                using (dynAppServ.DocumentContext ctx = new dynAppServ.DocumentContext(document.AcDocument))
                {
                    acDbServ.Transaction tr = ctx.Transaction; 

                    cdDbServ.Corridor obj = tr.GetObject(@object.InternalObjectId, acDbServ.OpenMode.ForRead) as cdDbServ.Corridor;
                    if (obj != null) { return new CustomCorridor(obj, false); }
                }
            }
            catch (System.Exception) { }

            return null;
        }


    }

}

This example does not have a function to create a new object, but if you write such a thing you need to use:

return new CustomCorridor(obj, true);

instead of

return new CustomCorridor(obj, false);

With true it becomes DynamoOwned and will be used in the trace mechanism.

Awesome. I’ve been looking for such examples. Informative. Thank u.

1 Like

Good luck! Hope it will help you :slight_smile:

When you provided a constructor for your class that takes arguments, the compiler no longer creates an empty constructor. Therefore, you cannot call an empty constructor because it does not exist. You would need to explicitly write the constructor that takes 0 arguments in your class’s code. The constructor of the inheritance class needs to construct the base class first. since the base class does not have a default constructor (taking 0 arguments) and you are not using the non-default constructor you have now, this won’t work. so either:

  • Add a default constructor to your base class, in which case the code of the descending class needs no change;

Or

  • Call the non-default constructor of the base class from the constructor of the descending class, in which case the base class needs no change.
1 Like