Вызов статического метода для параметра общего типа
Я надеялся сделать что-то подобное, но в С# он выглядит незаконным:
public Collection MethodThatFetchesSomething<T>()
where T : SomeBaseClass
{
return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}
Я получаю ошибку времени компиляции: "'T' - это параметр типа, который недопустим в данном контексте.
Учитывая параметр generic type, как я могу вызвать статический метод для универсального класса? Статический метод должен быть доступен с учетом ограничения.
Ответы
Ответ 1
В этом случае вам нужно просто вызвать статический метод на ограниченном типе напрямую. С# (и CLR) не поддерживают виртуальные статические методы. Итак:
T.StaticMethodOnSomeBaseClassThatReturnsCollection
... может не отличаться:
SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection
Прохождение общего параметра типа является ненужным косвенным и, следовательно, не поддерживается.
Ответ 2
Чтобы уточнить предыдущий ответ, я думаю, что размышление ближе к тому, что вы хотите здесь. Я мог бы дать 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, но он отвечает на заданный вопрос.
Ответ 3
Единственный способ вызова такого метода - через отражение. Тем не менее, похоже, что можно было бы обернуть эту функциональность в интерфейсе и использовать шаблон IoC/ factory/etc на основе экземпляра.
Ответ 4
Похоже, вы пытаетесь использовать дженерики, чтобы обойти тот факт, что в С# нет "виртуальных статических методов".
К сожалению, это не сработает.
Ответ 5
На данный момент вы не можете. Вам нужно указать компилятору, что T имеет этот метод, и в настоящее время нет никакого способа сделать это. (Многие подталкивают Microsoft расширять то, что может быть указано в общем ограничении, поэтому, возможно, это будет возможно в будущем).
Ответ 6
Здесь я пишу пример, который работает, это обходное решение
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();
}
Ответ 7
Вы должны иметь возможность сделать это с помощью отражения, как описано здесь
Ответ 8
Я просто хотел выбросить его там, что иногда делегаты решают эти проблемы, в зависимости от контекста.
Если вам нужно вызвать статический метод как своего рода метод factory или инициализации, то вы можете объявить делегат и передать статический метод соответствующему универсальному factory или тому, что ему нужно, это "общий класс с помощью этого статического метода".
Например:
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();
}
}
К сожалению, вы не можете обеспечить, чтобы класс имел правильный метод, но вы, по крайней мере, можете скомпилировать время, чтобы полученный метод factory имел все, что он ожидает (т.е. метод инициализации с точно подобранной сигнатурой). Это лучше, чем исключение отражения времени выполнения.
Этот подход также имеет некоторые преимущества, то есть вы можете повторно использовать методы init, использовать их как методы экземпляра и т.д.