Вызов статического метода для параметра универсального типа - PullRequest
94 голосов
/ 13 октября 2008

Я надеялся сделать что-то подобное, но это кажется незаконным в C #:


public Collection MethodThatFetchesSomething<T>()
    where T : SomeBaseClass
{
    return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}

Я получаю ошибку во время компиляции: «T» является «параметром типа», который недопустим в данном контексте. »

Учитывая параметр универсального типа, как я могу вызвать статический метод для универсального класса? Статический метод должен быть доступен с учетом ограничения.

Ответы [ 8 ]

52 голосов
/ 13 октября 2008

В этом случае вам нужно просто вызвать статический метод для ограниченного типа напрямую. C # (и CLR) не поддерживают виртуальные статические методы. Итак:

T.StaticMethodOnSomeBaseClassThatReturnsCollection

... не может отличаться от:

SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection

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

25 голосов
/ 02 декабря 2011

Чтобы уточнить предыдущий ответ, я думаю, что рефлексия ближе к тому, что вы хотите здесь. Я мог бы привести 1001 причину, по которой вы должны или не должны что-то делать, я просто отвечу на ваш вопрос в том виде, в котором он был задан. Я думаю, что вы должны вызвать метод GetMethod для типа универсального параметра и перейти оттуда. Например, для функции:

public void doSomething<T>() where T : someParent
{
    List<T> items=(List<T>)typeof(T).GetMethod("fetchAll").Invoke(null,new object[]{});
    //do something with items
}

Где T - любой класс, имеющий статический метод fetchAll ().

Да, я знаю, что это ужасно медленно и может произойти сбой, если someParent не заставляет все свои дочерние классы реализовывать fetchAll, но отвечает на вопрос в ответ на вопрос.

7 голосов
/ 13 октября 2008

Единственный способ вызова такого метода - это отражение, однако, похоже, что можно обернуть эту функциональность в интерфейсе и использовать шаблон IoC / factory / etc на основе экземпляра.

5 голосов
/ 13 октября 2008

Звучит так, как будто вы пытаетесь использовать универсальные шаблоны, чтобы обойти тот факт, что в C # нет "виртуальных статических методов".

К сожалению, это не сработает.

2 голосов
/ 28 декабря 2011

Я просто хотел показать, что иногда делегаты решают эти проблемы в зависимости от контекста.

Если вам нужно вызывать статический метод как своего рода метод фабрики или инициализации, тогда вы можете объявить делегат и передать статический метод в соответствующую универсальную фабрику или тому, кому нужен этот "универсальный класс с этим статическим метод».

Например:

class Factory<TProduct> where TProduct : new()
{
    public delegate void ProductInitializationMethod(TProduct newProduct);


    private ProductInitializationMethod m_ProductInitializationMethod;


    public Factory(ProductInitializationMethod p_ProductInitializationMethod)
    {
        m_ProductInitializationMethod = p_ProductInitializationMethod;
    }

    public TProduct CreateProduct()
    {
        var prod = new TProduct();
        m_ProductInitializationMethod(prod);
        return prod;
    }
}

class ProductA
{
    public static void InitializeProduct(ProductA newProduct)
    {
        // .. Do something with a new ProductA
    }
}

class ProductB
{
    public static void InitializeProduct(ProductB newProduct)
    {
        // .. Do something with a new ProductA
    }
}

class GenericAndDelegateTest
{
    public static void Main()
    {
        var factoryA = new Factory<ProductA>(ProductA.InitializeProduct);
        var factoryB = new Factory<ProductB>(ProductB.InitializeProduct);

        ProductA prodA = factoryA.CreateProduct();
        ProductB prodB = factoryB.CreateProduct();
    }
}

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

Этот подход также имеет некоторые преимущества, т.е. вы можете повторно использовать методы init, иметь их как методы экземпляра и т. Д.

2 голосов
/ 20 января 2009

Здесь я публикую пример, который работает, это обходной путь

public interface eInterface {
    void MethodOnSomeBaseClassThatReturnsCollection();
}

public T:SomeBaseClass, eInterface {

   public void MethodOnSomeBaseClassThatReturnsCollection() 
   { StaticMethodOnSomeBaseClassThatReturnsCollection() }

}

public Collection MethodThatFetchesSomething<T>() where T : SomeBaseClass, eInterface
{ 
   return ((eInterface)(new T()).StaticMethodOnSomeBaseClassThatReturnsCollection();
}
2 голосов
/ 13 октября 2008

На данный момент вы не можете. Вам нужен способ сообщить компилятору, что T имеет этот метод, и в настоящее время нет способа сделать это. (Многие подталкивают Microsoft расширить то, что может быть указано в общем ограничении, так что, возможно, это будет возможно в будущем).

1 голос
/ 13 февраля 2011

Вы должны быть в состоянии сделать это с помощью отражения, как описано здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...