メソッド内のボックス化された値型を変更する方法
-
08-07-2019 - |
質問
C#で遅延バインディング呼び出しを単純化するためのライブラリを構築しようとしていますが、参照パラメーターを使用して問題を追跡しています。メソッド呼び出しで使用されるパラメーターを追加するには、次のメソッドがあります
public IInvoker AddParameter(ref object value)
{
//List<object> _parameters = new List<object>();
_parameters.Add(value);
//List<bool> _isRef = new List<bool>();
_isRef.Add(true);
return this;
}
そして、それはオブジェクトとしてボックス化され、変更されないため、値型では機能しません。例:
int param1 = 2;
object paramObj = param1;
//MulFiveRef method multiplies the integer passed as a reference parameter by 5:
//void MulFiveRef(ref int value) { value *= 5; }
fi.Method("MulFiveRef").AddParameter(ref paramObj);
それは機能しません。遅延バインディング呼び出しは成功し、パラメーター(_parameters)を保持する内部リストは変更されますが、呼び出しの外部の値は変更されません。
この制限を克服する簡単な方法を知っている人はいますか? 遅延バインディング呼び出しの場合、AddParameterシグネチャを変更することはできません。パラメーターのTypeを事前に知ることはできません(また、呼び出しを行う前にオブジェクト配列内に呼び出しのすべてのパラメーターを挿入することもできません)
事前に感謝します。
解決
値がメソッド内で変化している場合 、渡す( ref
)に一時( object
)変数を宣言する必要がありますメソッドを作成し、後で自分でボックスを開きます:
int i = 3;
//...
object obj = i;
Foo(ref obj);
i = (int)obj;
これにより、イベント後に値を更新できないことに注意してください。イベントやコールバックのようなものは、変更を呼び出し元に戻す別の方法かもしれません。
C#4.0には、COM呼び出しのコンテキストで only を支援するいくつかのトリックもあります( refオブジェクト
は非常に一般的です[もちろん Jonが指摘しているように、遅延バインディングの動的
。)
他のヒント
とにかくメソッドは value
を変更していません-なぜそれを参照渡しするのですか?それは理にかなっているかもしれませんが、私には本当に明確ではありません。 ref
引数は正確にパラメータと同じ型である必要があるため、提供したサンプルコードはコンパイルできません。
(また、C#4.0と.NET 4.0にはレイトバインディングのサポートが組み込まれていることをご存知ですか?言語統合バージョンは、ライブラリのみのバージョンよりも使いやすい可能性があります。この時点でライブラリに時間を費やす価値はありますか?)
編集:指定したコードは実際にはコンパイルされません。引数とパラメーターの型が正確に同じでなければならないため、 ref
パラメーターのボクシングは行われません。これを証明するサンプルコードを次に示します。
public class Test
{
static void Main()
{
int i;
Foo(ref i); // Won't compile - error CS1502/1503
}
static void Foo(ref object x)
{
}
}
現在のコードが コンパイル中の場合、質問で提示したコードではありません。おそらく ref int
を受け入れる AddParameter
の別のオーバーロードがありますか?
Ok、Jon Skeetの修正とMark Gravellのコードのおかげで、私はこのインターフェースを思いつきました:
//This will be created with a factory
IOperationInvoker invoker = new OperationInvoker(Activator.CreateInstance<MyLateBindingTestType>());
int param1 = 2;
object paramObj = param1;
invoker.AddParameter(ref paramObj).Invoke("MulFiveRef");
param1 = (int)invoker.Parameters[0];
私が想像したほど正確ではありませんが、以前のインターフェイスよりもずっと簡単で読みやすいです:
IOperationInvoker invoker = new OperationInvoker(Activator.CreateInstance<MyLateBindingTestType>());
int refValue = 10;
object[] args = Args.Build(refValue);
invoker.Call("MulFiveRef", Args.ByRefIndexs(0), args);
refValue = (int)args[0];
助けてくれてありがとうございます:)