Method execution improvements, HasMethod() / HasType()

When using IScriptHost.RunMethod() or IScriptRun.RunMethod() there is no guarantee that the class or method does exists in the script.

If a class or method does not exists, there will is no exception thrown or indicator that the method was not run at all. Just no code is executed.

Is there a way to lookup a method / class beforehand, so that i can check if those exists? Like IScriptHost.HasMethod(string methodName) and IScriptRun.HasMethod(string methodName)?

In addition having a IScriptRun.HasType(Type type) / IScriptRun.HasType(string typeName) would be useful too.

Of course the best way in my oppinion would be that the RunMethod() throws an Exception or returns either a Error State or the resulting type. For that something like OneOf<> would be perfect. In addition you could add another signature for RunMethod() and RunMethodAsync() that allows to set a generic for the resulting type.

For the moment, is there a workaround for looking up the method in the AST?

We have already implemented HasMethod and FindMethod in the master branch and will include this feature in the next build. As for HasType and the generic version of RunMethod, I will study them and respond to you shortly. In the meantime, you can use the ScriptAssembly property after you compile the script. This property allows you to access any script method or property via reflection.

Here is an example for VB:

Dim assembly = ScriptRun1.ScriptHost.ScriptAssembly
Dim inst = assembly.CreateInstance("ScriptSpace.ScriptClass")

Dim propInfoShared = inst.GetType().GetProperty("GlobalProp")

propInfoShared.SetValue(Nothing, "new shared value from main app")
Dim valShared = propInfoShared.GetValue(Nothing)

Dim propInfoInstance = inst.GetType().GetProperty("InstanceProp")
propInfoInstance.SetValue(inst, "new instance value from main app")
Dim valInstance = propInfoInstance.GetValue(inst)

In script:

Imports System
Imports System.Drawing
Imports System.Diagnostics
Imports System.Windows.Forms
Imports Microsoft.VisualBasic

Namespace ScriptSpace
    Partial Public Class ScriptClass

        Public Shared ReadOnly Property SharedDefault As ScriptClass = New ScriptClass()

        ' Instance field initialized inline
        Private count As Integer = 5

        ' Shared (static) field initialized inline
        Public Shared globalVar As String = "olala"

        ' Compile-time constant
        Public Const Pi As Double = 3.14159265358979

        Public Shared Property GlobalProp As String
            Get
                Return globalVar
            End Get
            Set(value As String)
                globalVar = value
            End Set
        End Property

        Public Property InstanceProp As String
            Get
                Return globalVar
            End Get
            Set(value As String)
                globalVar = value
            End Set
        End Property

        ' Read-only field - can be initialized inline or in the constructor
        Private ReadOnly createdAt As Date = Date.UtcNow

        Public Shared Sub Main(text As String)
            MsgBox("Main app says: " & text & " and " & globalVar)
            External.X = 10
            External.MainWindowText = "Text set from ScriptClass"
        End Sub

        Public Shared Function GetData() As Integer
            Return External.X
        End Function
    End Class
End Namespace

We have also added an additional parameter to RunMethod that specifies whether to throw an exception when the method is not found. This feature will also be available in the next build. I will post an update here when the new build is available and on how we will proceed with the other features you requested.

In the new build we also added HasType and FindType. See the FindType source code for an example of how to work with ScriptAssembly property.

/// <summary>
/// Determines whether a type with the specified name exists in the script assembly.
/// </summary>
/// <param name="typeName">The name of the type to locate. This value is case-sensitive and cannot be null or empty.</param>
/// <returns>true if a type with the specified name exists; otherwise, false.</returns>
public virtual bool HasType(string typeName, bool ignoreCase = false)
{
    return FindType(typeName, ignoreCase: ignoreCase) != null;
}

/// <summary>
/// Searches for a type with the specified name in the script assembly and returns its metadata if found.
/// </summary>
/// <param name="typeName">The fully qualified name of the type to locate. Cannot be null or empty.</param>
/// <param name="ignoreCase">true to ignore case when searching for the type; otherwise, false.
/// Optional. Default is false.</param>
/// <param name="throwOnError">true to throw an exception if the type is not found; otherwise, false.
/// Optional. Default is false.</param>
/// <returns>A <see cref="Type"/> object representing the type with the specified name, or null if the type is not found.</returns>
public virtual Type FindType(string typeName, bool throwOnError = false, bool ignoreCase = false)
{
    return Compiled || Compile() ? FindTypeInternal() : null;

    Type FindTypeInternal()
    {
        var assembly = ScriptAssembly;
        if (assembly == null)
            return null;
        return assembly.GetType(typeName, throwOnError: throwOnError, ignoreCase: ignoreCase);
    }
}

Awesome, thats exactly what i was looking for. Thanks for adding that.

We have just released Alternet.Studio build 10.0.7, which includes the features you requested. You will shortly receive a notification about the library update.