2016-10-16 52 views
1

我使用IronPython的方法,我知道如何從我的類暴露的方法來腳本的範圍: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類中獲取它們。

回答

0

處理與一個參數的方法,你可以使用此代碼:

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<,,>,依此類推。

一個不那麼優雅,但快速的方法是預先分配與各類型行動的數組:

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

如果我的方法根本不需要參數?那麼我將如何獲得這種類型?另外,有沒有辦法根據參數計數來獲取類型,所以我可以將其擴展到任何我想要的參數數量,而不是將自己限制爲一個? –

+0

好的,我明白了。這就是我想要做的。絕對不是優雅,但很聰明。 –

+0

當我試圖添加一個不帶參數的動作時,我得到一個InvalidOperatioNException,它說:System.Action不是GenericTypeDefinition。 MakeGenericType只能在Type.IsGenericTypeDefinition爲true的類型上調用。 –