62

オプションのパラメーターを指定してC#4.0を使用すると、別の問題が発生しました。

ConstructorInfoパラメーターを必要としないことがわかっている関数(またはコンストラクター、オブジェクトがあります)を呼び出すにはどうすればよいですか?

これが私が今使っているコードです:

type.GetParameterlessConstructor()
    .Invoke(BindingFlags.OptionalParamBinding | 
            BindingFlags.InvokeMethod | 
            BindingFlags.CreateInstance, 
            null, 
            new object[0], 
            CultureInfo.InvariantCulture);

(私は別の方法で試しましたBindingFlags)。

GetParameterlessConstructorのために書いたカスタム拡張メソッドですType

4

5 に答える 5

136

MSDNによると、デフォルトのパラメータを使用するには、を渡す必要がありますType.Missing

Type.Missingコンストラクターに3つのオプションの引数がある場合、空のオブジェクト配列を渡す代わりに、各要素の値が次の3要素のオブジェクト配列を渡します。

type.GetParameterlessConstructor()
    .Invoke(BindingFlags.OptionalParamBinding | 
            BindingFlags.InvokeMethod | 
            BindingFlags.CreateInstance, 
            null, 
            new object[] { Type.Missing, Type.Missing, Type.Missing }, 
            CultureInfo.InvariantCulture);
于 2012-03-28T21:52:01.290 に答える
23

オプションのパラメーターは通常の属性で示され、コンパイラーによって処理されます。
これらはILに(メタデータフラグ以外の)影響を与えず、リフレクションによって直接サポートされません(IsOptionalおよびDefaultValueプロパティを除く)。

リフレクションでオプションのパラメータを使用する場合は、デフォルト値を手動で渡す必要があります。

于 2010-03-11T01:47:44.607 に答える
3

コードを追加するだけです...なぜなら。コードは満足のいくものではありません、私は同意しますが、それはかなり簡単です。うまくいけば、これはこれに遭遇する誰かを助けるでしょう。テストされていますが、実稼働環境で必要なほどではない可能性があります。

引数argsを使用してオブジェクトobjでメソッドmethodNameを呼び出す:

    public Tuple<bool, object> Evaluate(IScopeContext c, object obj, string methodName, object[] args)
    {
        // Get the type of the object
        var t = obj.GetType();
        var argListTypes = args.Select(a => a.GetType()).ToArray();

        var funcs = (from m in t.GetMethods()
                     where m.Name == methodName
                     where m.ArgumentListMatches(argListTypes)
                     select m).ToArray();

        if (funcs.Length != 1)
            return new Tuple<bool, object>(false, null);

        // And invoke the method and see what we can get back.
        // Optional arguments means we have to fill things in.
        var method = funcs[0];
        object[] allArgs = args;
        if (method.GetParameters().Length != args.Length)
        {
            var defaultArgs = method.GetParameters().Skip(args.Length)
                .Select(a => a.HasDefaultValue ? a.DefaultValue : null);
            allArgs = args.Concat(defaultArgs).ToArray();
        }
        var r = funcs[0].Invoke(obj, allArgs);
        return new Tuple<bool, object>(true, r);
    }

そして、関数ArgumentListMatchesは以下のとおりです。これは、基本的にGetMethodにあるロジックの代わりになります。

    public static bool ArgumentListMatches(this MethodInfo m, Type[] args)
    {
        // If there are less arguments, then it just doesn't matter.
        var pInfo = m.GetParameters();
        if (pInfo.Length < args.Length)
            return false;

        // Now, check compatibility of the first set of arguments.
        var commonArgs = args.Zip(pInfo, (margs, pinfo) => Tuple.Create(margs, pinfo.ParameterType));
        if (commonArgs.Where(t => !t.Item1.IsAssignableFrom(t.Item2)).Any())
            return false;

        // And make sure the last set of arguments are actually default!
        return pInfo.Skip(args.Length).All(p => p.IsOptional);
    }

たくさんのLINQがあり、これはパフォーマンステストされていません!

また、これはジェネリック関数またはメソッド呼び出しを処理しません。これにより、これは非常に醜くなります(GetMethod呼び出しを繰り返す場合のように)。

于 2015-03-19T22:55:52.620 に答える
2

コードが逆コンパイルされると、すべての質問が消えます。

c#:

public MyClass([Optional, DefaultParameterValue("")]string myOptArg)

msil:

.method public hidebysig specialname rtspecialname instance void .ctor([opt]string myOptArg) cil managed 

ご覧のとおり、オプションのパラメータは、特定の属性で装飾された実際の個別のエンティティであり、前述のように、リフレクションを介して呼び出す場合はそれに応じて尊重する必要があります。

于 2016-04-04T08:00:36.337 に答える
1

バージョン4以降のオープンソースフレームワークImpromptuInterfaceを使用すると、C#4.0のDLRを使用して、非常に遅い方法でコンストラクターを呼び出すことができ、名前付き/オプションの引数を持つコンストラクターを完全に認識します。これは、4倍速く実行さActivator.CreateInstance(Type type, params object[] args)れます。デフォルト値を反映します。

using ImpromptuInterface;
using ImpromptuInterface.InvokeExt;

..。

//if all optional and you don't want to call any
Impromptu.InvokeConstructor(type)

また

//If you want to call one parameter and need to name it
Impromptu.InvokeConstructor(type, CultureInfo.InvariantCulture.WithArgumentName("culture"))
于 2011-04-16T23:11:54.383 に答える