簡體   English   中英

IronPython - 使用反射公開方法

[英]IronPython - Exposing methods using reflection

我正在使用IronPython,我知道如何將類中的方法暴露給腳本的范圍:

m_scope.SetVariable("log", new Action<string>(Log));

public void Log(string a)
{
    Console.WriteLine(a);
}

但是,每次我想使用反射加速進程時,而不是調用SetVariable 所以,我創建了一個名為ScriptMethodAttribute的屬性:

public sealed class ScriptMethodAttribute : Attribute
{
    public string Name { get; private set; }

    public ScriptMethodAttribute(string name)
    {
        Name = name;
    }
}

這樣,我可以在我的類中定義腳本使用的方法,如下所示:

[ScriptMethod("log")]
public void Log(string a)
{
    Console.WriteLine(a);
}

現在我想在每個使用此屬性的方法上調用SetVariable來加速進程。 但是,這似乎不起作用。

這是一個實用程序方法,它返回Tuple<ScriptMethodAttribute, MethodInfo的列表。

public static IEnumerable<Tuple<TAttribute, MethodInfo>> FindMethodsByAttribute<TAttribute>()
        where TAttribute : Attribute
{
    return (from method in AppDomain.CurrentDomain.GetAssemblies()
                    .Where(assembly => !assembly.GlobalAssemblyCache)
                    .SelectMany(assembly => assembly.GetTypes())
                    .SelectMany(type => type.GetMethods())
                let attribute = Attribute.GetCustomAttribute(method, typeof(TAttribute), false) as TAttribute
                where attribute != null
                select new Tuple<TAttribute, MethodInfo>(attribute, method));
}

這位於我腳本的類構造函數中:

foreach (var a in Reflector.FindMethodsByAttribute<ScriptMethodAttribute>())
{
    Action action = (Action)Delegate.CreateDelegate(typeof(Action), this, a.Item2);

    m_scope.SetVariable(a.Item1.Name, action);
}

我收到以下異常:

System.ArgumentException: Cannot bind to the target method because its signature or security transparency is            not compatible with that of the delegate type.

我猜它是因為我必須在Action構造函數中包含所需的類型,但我不知道如何從MethodInfo類中獲取它們。

要使用一個參數處理方法,可以使用以下代碼:

var parameters = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();

var delegateType = typeof(Action<>).MakeGenericType(parameters);

var action = methodInfo.CreateDelegate(delegateType, this);

// Now you can call m_scope.SetVariable with action

如果要處理具有任意數量參數的方法,事情會變得更加棘手,因為您需要根據parameters數組中的元素數添加一些分支。 如果有兩個元素,那么你需要使用Action<,>而不是Action<> ,如果有三個你需要使用Action<,,> ,依此類推。

一種不那么優雅但快速的方法是使用每種類型的Action預分配數組:

private Type[] DelegateTypes = new[]
{
    typeof (Action),
    typeof (Action<>),
    typeof (Action<,>),
    typeof (Action<,,>),
    typeof (Action<,,,>),
    typeof (Action<,,,,>),
    typeof (Action<,,,,,>),
    typeof (Action<,,,,,,>),
    typeof (Action<,,,,,,,>),
    typeof (Action<,,,,,,,,>),
    typeof (Action<,,,,,,,,,>),
    typeof (Action<,,,,,,,,,,>),
    typeof (Action<,,,,,,,,,,,>),
    typeof (Action<,,,,,,,,,,,,>),
    typeof (Action<,,,,,,,,,,,,,>),
    typeof (Action<,,,,,,,,,,,,,,>),
    typeof (Action<,,,,,,,,,,,,,,,>)
};

從那里,只需訪問數組的正確索引,具體取決於您的參數數量:

Type delegateType;

if (parameters.Length == 0)
    delegateType = DelegateTypes[0];
else
    delegateType = DelegateTypes[parameters.Length].MakeGenericType(parameters);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM