system.typeから一般的なタイプを使用してジェネリックメソッドを呼び出す
-
27-10-2019 - |
質問
以下はコードの例と質問です。C#4.0と動的キーワードは使用できないことに注意してください。
static class TestClass
{
static void Main(string[] args)
{
Object o = "Previous value";
Test(ref o);
Trace.WriteLine(o);
}
static public void Test<T>(ref T obj)
{
// The goal is to somehow invoke Test2 with the real type of obj, i.e the type in obj.GetType()
// 1st try:
Test2(ref obj); // This doesn't work because the type in Test2 will be the same as T here.
// 2nd try:
MethodInfo mi = typeof(TestClass).GetMethod("Test2");
mi = mi.MakeGenericMethod(new Type[] { obj.GetType() });
mi.Invoke(null, new Object[] { obj }); // obj is no longer by reference so we need to store the object array and copy back the result after the call
// 3rd try, successful implementation by the smartest mind of stack overflow :)
}
static public void Test2<T>(ref T s)
{
if (typeof(T) == typeof(String))
{
s = (T)(Object)"Hello world!";
}
}
}
また、DeLegate.CreatedElegateを使用してさらにいくつかの方法を試しましたが、運はありませんでした。これは可能ですか?
編集:私は動的な方法(およびMSILアセンブラー)を使用することを恐れていませんが、この分野での私の知識は非常に限られています。
edit2:私が本当にやろうとしていることに近い例を次に示します。
public static class TypeHandler<T>
{
public delegate void ProcessDelegate(ref T value);
public static readonly ProcessDelegate Process = Init();
private static ProcessDelegate Init()
{
// Do lot's of magic stuff and returns a suitable delegate depending on the type
return null;
}
}
static class TestClass
{
static public void Main(string[] args)
{
Object o = "Previous value";
Test(ref o);
Trace.WriteLine(o);
}
static public void Test<T>(ref T obj)
{
if (obj is T)
{
// Optimized, common case
TypeHandler<T>.Process(ref obj);
return;
}
Type t = obj.GetType();
// How to call the delegate found in TypeHandler<t>.Process ? (I can get delegate but I can't call it).
}
}
解決
更新3: :わかりました、醜い解決策で大丈夫なので、チェックアウトすることができます 文書化されていない __refvalue
と __makeref
キーワード.
あなたの問題は、あなたがのタイプを指定できるようにしたいということです ref object
パラメーターがあります 変換された また かわった に。
それに関する問題は、あらゆるタイプの変数を任意に割り当てることができないことです T
に string
, 、 例えば。したがって、aで渡す必要があります ref object
また ref string
それが機能するために まったく.
それは私には見えます Oberfreak あなたが達成しようとしていたことを釘付けにしました(私はあなたが初期化されていたことに気づかなかった o
として string
したがって、明らかにそれを望んでいました 実際 の動作に影響を与えるためにタイプ Test2
関数)。彼の答えはあなたにとって正しいアプローチを持っています。
アップデート: :コメントで、あなたがやろうとしていることは、辞書を使用して達成できる動的な動作を持っていることです。私はそれがこのようなものに見えると思いますか?
更新2: : 更新しました これ に基づいた例 君の 更新された例。
public static class TypeHandler // note: get rid of generic T parameter
{
delegate void ProcessDelegate(ref object obj); // again, not generic
static Dictionary<Type, ProcessDelegate> processors = new Dictionary<Type, ProcessDelegate>()
{
{ typeof(string), (ref object obj) => { obj = "Hello, world!"; } }
// etc.
};
public static void Process(ref object obj)
{
processors[obj.GetType()].Invoke(ref obj);
}
}
それか 動作するはずです。しかし、これを行う方法がないので、ジェネリックと同じことを実際に達成することはできません。
// not allowed
// |
// -----------
// | |
TypeHandler<o.GetType()>.Process(ref o);
もしそこにあるなら そうだった, 、それからあなたはすべて設定されるでしょう。しかし、それを行う唯一の可能な方法は、このようなものにとって醜くて高価なリフレクションを使用することです。
他のヒント
あなたのコメントはあなたがすでにそれをする方法をすでに理解しているように見えます:
MethodInfo mi = typeof(TestClass).GetMethod("Test2");
mi = mi.MakeGenericMethod(new Type[] { obj.GetType() });
object[] args = new object[] { obj };
mi.Invoke(null, args);
obj = (T) args[0];
それは本当にあなたのコメントをコードに変えるだけです。それはどういうわけかあなたが望むことをしませんか?
私の意見では、主な質問は、あなたが何をしたいのかということです。
参照オブジェクトに文字列を割り当てたい場合は、これを試すことができます。
ジェネリックはランタイム中に定義することができますが、それはVerryが快適ではなく、反省によって行われなければなりません...私の意見ではそれは「ノーゴー」ですが、ただの意見です
を使用してみてください object.GetType()
オブジェクトの現在のタイプを取得します。
static class TestClass {
static void Main(string[] args) {
Object o = "Previous value";
Test(ref o);
Console.WriteLine(o);
Console.ReadLine();
}
static public void Test<T>(ref T obj) {
Object o = (Object)obj;
Test2(ref o);
obj = (T)o;
}
static public void Test2(ref object s) {
if (s.GetType().Equals(typeof(String))) {
s = "Hello world!";
}
}
}
メソッドTest2を実装する正しい方法はそうです
static public void Test2<T>(ref T s)
{
if (s is string)
{
s = (T)(Object)"Hello world!";
}
}
それとも私はここで何かが足りませんか?
変更できる場合 ref
定期的に返品するには、4.0で大量にcheすることができます dynamic
:
dynamic foo = obj;
Test(foo);
それは今です:
Test<TheActualTypeOfObj>(obj);
完全な例:
static void Main(string[] args)
{
object o = "Previous value";
o = Test2((dynamic)o);
Trace.WriteLine(o);
}
static public T Test2<T>(T s)
{
if (typeof(T) == typeof(string))
{
s = (T)(object)"Hello world!";
}
return s;
}
「Hello World!」と書いています。