私はジェネリッククラスを持っています:
public class MyList<LinkedItem> : List<LinkedItem> where LinkedItem : MyItem, new()
{
}
そのジェネリック クラスから、MyItem クラスの子孫である LinkedItem クラスから静的関数にアクセスしたいと思います。(したがって、LinkedItem のインスタンスを作成せずに)。
出来ますか?
ありがとうございました、
エリック
私はジェネリッククラスを持っています:
public class MyList<LinkedItem> : List<LinkedItem> where LinkedItem : MyItem, new()
{
}
そのジェネリック クラスから、MyItem クラスの子孫である LinkedItem クラスから静的関数にアクセスしたいと思います。(したがって、LinkedItem のインスタンスを作成せずに)。
出来ますか?
ありがとうございました、
エリック
それは反射を通して行うことができます。C#には静的メンバーに対するAPI制約がないため、これを行う簡単な方法はありません。
現在のシナリオはわかりませんが、ほとんどの場合、これは推奨される解決策ではありません:)
public class MyList<LinkedItem> : List<LinkedItem>
where LinkedItem : MyItem, new()
{
public int CallStaticMethod()
{
// Getting a static method named "M" from runtime type of LinkedItem
var methodInfo = typeof(LinkedItem)
.GetMethod("M", BindingFlags.Static | BindingFlags.Public);
// Invoking the static method, if the actual method will expect arguments
// they'll be passed in the array instead of empty array
return (int) methodInfo.Invoke(null, new object[0]);
}
}
public class MyItem
{
}
class MyItemImpl : MyItem
{
public MyItemImpl()
{
}
public static int M()
{
return 100;
}
}
したがって、たとえば次のコードは次のように出力します100
。
public void Test()
{
Console.WriteLine(new MyList<MyItemImpl>().CallStaticMethod());
}
はい、可能ですが、リフレクションを使用して MethodInfo を取得しtypeof(T).GetMethod("Foo", BindingFlags.Public | BindingFlags.Static)
、それを呼び出すInvoke
必要があります。
特に MethodInfo ではなく ConstructorInfo で同じ手法を使用する場合、コンストラクターでパラメーターを使用するジェネリック ファクトリを作成すると非常に便利です。とはいえ、控えめに使うものです。特に、問題の型が必要な署名の静的メソッドを持っていることをコンパイル時に保証する方法がないため、型の安全性がなくなり、そのようなエラーは実行時までキャッチされません。
いいえ、ジェネリック型パラメーターで静的メソッドを呼び出すことができないため、型パラメーターから直接これを行うことはできません (C# Lang Spec セクション 4.5)。
静的メンバーまたはネストされた型を識別するために、型パラメーターをメンバー アクセス (§7.5.4) または型名 (§3.8) で使用することはできません。
はい、他の人が指摘したように、これはリフレクション トリックを介して達成することが可能です。しかし、一般的に言えば、単純なメソッド呼び出しシナリオを解決するためにリフレクションを使用することは、設計が悪いことを示しています。
はるかに優れた設計は、静的メソッドをタイプセーフな方法でカプセル化するファクトリ/デリゲートを渡すことです。
class MyItem : MyItem {
static void TheFunction() { ... }
}
public class MyList<LinkedItem> : List<LinkedItem> where LinkedItem : MyItem, new()
{
public MyList(Action theStaticFunction) {
...
}
}
new MyList<MyItem>(MyItem.TheFunction);
これは不可能です。LinkedItem
問題の静的メソッドを含める必要があるというパラメーターの制約を宣言する方法はありません。
おそらく最も近いのは次のとおりです。
public class ILinkedItemFactory<T>
{
void YourMethodGoesHere();
}
public class MyList<LinkedItem, Factory> : List<LinkedItem>
where Factory : ILinkedItemFactory<LinkedItem>
where LinkedItem : MyItem, new()
{
public MyList(Factory factory)
{
factory.YourMethodGoesHere();
}
}
デフォルトでは、これは不可能です。ただし、呼び出したいメソッドの名前が分かっていて、すべてLinkedItem
の型にこのメソッドが含まれていることが確実な場合は、リフレクションを使用して目標を達成できます。注: 一般的なプログラミング タスクでは、リフレクションに解決するよりも良い方法がよくあります。
以下は、常に に対して出力true
されDoSomething
ます。常に使用可能な静的メンバーを呼び出します (静的メソッドでは重要ではないため、ジェネリック型の制約を削除しました)。
public class MyList<LinkedItem> : List<LinkedItem>
{
public bool DoSomething()
{
Type t = typeof(LinkedItem);
object o = new Object();
var result = t.InvokeMember("ReferenceEquals",
BindingFlags.InvokeMethod |
BindingFlags.Public |
BindingFlags.Static,
null,
null, new[] { o, o });
return (result as bool?).Value;
}
}
// call it like this:
MyList<string> ml = new MyList<string>();
bool value = ml.DoSomething(); // true
PS: 一方、私がこれを入力している間、他の人は同じアプローチを提案しているようです ;-)
これは完全に可能ですが、おそらく反省せずにあなたが述べている方法で直接ではありません。基本クラスに非静的アクセス メソッドを実装し、特定の継承クラスごとにオーバーライドする必要があります。
public class MyItem
{
public static void DoSomeStaticStuff() { //DoSomeStaticStuff for MyItem }
public virtual void AccessSomeStaticStuff() { MyItem.DoSomeStaticStuff(); }
}
public class SomeItem : MyItem
{
public static void DoSomeStaticStuff() { //DoSomeStaticStuff for SomeItem }
public override void AccessSomeStaticStuff() { SomeItem.DoSomeStaticStuff(); }
}
次に、 T : MyItem という制約を持つクラスで、 T.AccessSomeStaticStuff(); を呼び出すだけです。