Accessing static functions and properties declared in a base class

Apr 5, 2012 at 12:31 PM
Edited Apr 5, 2012 at 4:46 PM

Hi,

I am attempting to add static functions and properties (using the latest revision) to a base class and then have other classes inherit that class and then be exposed to the engine as instance classes. However, I have been unable to get the engine to recognise them, with the functions giving "is not a function" errors and properties simply returning undefined. If I move these into the inheriting class they work perfectly.

Is this just part of the way the engine works or should this be possible? And if so, how?

Thanks for your brilliant work on this super awesome library and I'm sorry if this is a stupid question.

EDIT: I am using VB.NET and the functions and properties are public and have the required attributes.

Sam.

Coordinator
Apr 6, 2012 at 11:29 AM

Basically this is caused by Jurassic passing in the BindingFlags.DeclaredOnly flag when searching for methods.  The reason it does this is that it expects that inherited methods will be handled via the javascript prototype chain, and not via .NET inheritance.

Apr 6, 2012 at 11:37 AM
Edited Apr 6, 2012 at 11:38 AM

Thanks for the response.

Is there a reason it expects that? Is what I am doing bad form in some way? I simply have an object that I associate with all controls on my form that allows certain properties to be set on them via javascript. I am inheriting it each time I use it because I have a few custom properties on each.

Coordinator
Apr 6, 2012 at 1:36 PM
Edited Apr 6, 2012 at 1:39 PM

Hmm, wait, are you calling PopulateFunctions() in the constructor of both types?  That should solve the problem.

public class Math1 : ObjectInstance
{
    public Math1(ScriptEngine engine)
        : base(engine)
    {
        this.PopulateFunctions();
    }

    [JSFunction(Name = "log")]
    public static double Log(double num)
    {
        return Math.Log(num);
    }
}

public class Math2 : Math1
{
    public Math2(ScriptEngine engine)
        : base(engine)
    {
        this.PopulateFunctions();
    }

    [JSFunction(Name = "log10")]
    public static double Log10(double num)
    {
        return Math.Log10(num);
    }
}

 

Alternatively, I have committed a change that lets you specify the binding flags, so you can specify BindingFlags.FlattenHeirarchy for example.

public class Math1 : ObjectInstance
{
    public Math1(ScriptEngine engine)
        : base(engine)
    {
    }

    [JSFunction(Name = "log")]
    public static double Log(double num)
    {
        return Math.Log(num);
    }
}

public class Math2 : Math1
{
    public Math2(ScriptEngine engine)
        : base(engine)
    {
        this.PopulateFunctions(this.GetType(), BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHeirarchy);
    }

    [JSFunction(Name = "log10")]
    public static double Log10(double num)
    {
        return Math.Log10(num);
    }
}
Apr 6, 2012 at 2:37 PM
Edited Apr 6, 2012 at 2:39 PM

Thanks, that's all pretty awesome!

I thought I had tried calling populateFunctions on both yesterday but it had not worked, although it does appear to now. Sorry for wasting your time with that. The binding flags addition is really cool though and I will probably end up using that.

Just one more thing if you don't mind: Is it correct that I should have to call populateFields any time any of them are changed in code in order to get them to update? I will probably end up changing most if not all of the fields to properties now that the capability exists but it just was not what I had expected from reading the documentation.

Thanks for your work on this awesome library and your very cool responses to my queries. I am yet to go through any kind of formal computing/programming education (I'm 15) so I'm sorry if any of these questions appear dumb.

EDIT: Not that it matters but I'm 16 not 15, I just keep forgetting I had a birthday a couple of months ago :D

Sam.

Coordinator
Apr 7, 2012 at 6:41 AM

PopulateFields is only used for constants.  You should use [JsProperty] instead, or just set JS properties when needed using this["propName"] = value (the second option is better performance-wise).

Apr 7, 2012 at 8:42 AM

Oh OK, thanks very much for your help.