Общий вопрос ... Вызов статического метода из универсального класса - PullRequest
3 голосов
/ 16 августа 2010

У меня есть общий класс:

public class MyList<LinkedItem> : List<LinkedItem> where LinkedItem : MyItem, new()
{
}

Из этого универсального класса я хотел бы получить доступ к статической функции из класса LinkedItem, который является потомком класса MyItem. (таким образом, без создания экземпляра LinkedItem).

Возможно ли это?

Спасибо,

Eric

Ответы [ 6 ]

2 голосов
/ 16 августа 2010

Да, это возможно, но вы должны использовать отражение, получая MethodInfo из typeof(T).GetMethod("Foo", BindingFlags.Public | BindingFlags.Static) и затем вызывая Invoke для него.

Это может быть очень полезно, особенно если используется тот же методна ConstructorInfo, а не MethodInfo, чтобы создать универсальную фабрику, которая использует параметры в конструкторе.Это хоть один, чтобы использовать экономно.В частности, нет способа гарантировать во время компиляции, что у рассматриваемого типа есть статический метод требуемой сигнатуры, поэтому безопасность типов исчезла, и такая ошибка не будет обнаружена до времени выполнения.

2 голосов
/ 16 августа 2010

Это можно сделать с помощью отражения. Прямого способа сделать это не существует, поскольку 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());
}
2 голосов
/ 16 августа 2010

Нет, это невозможно напрямую из параметра типа, потому что вы не можете вызывать статические методы для параметров универсального типа (C.5 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);
0 голосов
/ 16 августа 2010

Это вполне возможно, хотя не напрямую, как вы заявляете, возможно, без размышлений.Вы хотели бы реализовать нестатический метод доступа в базовом классе и переопределить его в каждом конкретном наследующем классе.

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 (); * +1004 *

0 голосов
/ 16 августа 2010

Это по умолчанию невозможно. Однако, если вам известно имя метода, который вы хотите вызвать, и вы уверены, что каждый тип 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: между тем, пока я печатал это, другие, похоже, предлагают такой же подход; -)

0 голосов
/ 16 августа 2010

Это невозможно. Нет никакого способа объявить ограничение на параметр 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();
    }
}
...