Каковы основные виды использования статического универсального класса в C #?Когда их следует использовать?Какие примеры лучше всего иллюстрируют их использование?
Я думаю, в общем, вам следует избегать создания параметров типов для статических классов, иначе вы не можете зависеть от вывода типов, чтобы сделать ваш клиентский код более лаконичным.
Чтобы привести конкретный пример, предположим, что вы пишете статический служебный класс для обработки операций над списками.Вы можете написать класс двумя способами:
// static class with generics
public static class ListOps<T>
{
public static List<T> Filter(List<T> list, Func<T, bool> predicate) { ... }
public static List<U> Map<U>(List<T> list, Func<T, U> convertor) { ... }
public static U Fold<U>(List<T> list, U seed, Func<T, U> aggregator) { ... }
}
// vanilla static class
public static class ListOps
{
public static List<T> Filter<T>(List<T> list, Func<T, bool> predicate) { ... }
public static List<U> Map<T, U>(List<T> list, Func<T, U> convertor) { ... }
public static U Fold<T, U>(List<T> list, U seed, Func<T, U> aggregator) { ... }
}
Но классы эквивалентны, но какой из них легче использовать?Сравните:
// generic static class
List<int> numbers = Enumerable.Range(0, 100).ToList();
List<int> evens = ListOps<int>.Filter(numbers, x => x % 2 = 0);
List<string> numberString = ListOps<int>.Map(numbers, x => x.ToString());
int sumOfSquares = ListOps<int>.Fold(numbers, 0, (acc, x) => acc + x*x);
// vanilla static class
List<int> numbers = Enumerable.Range(0, 100).ToList();
List<int> evens = ListOps.Filter(numbers, x => x % 2 = 0);
List<string> numberString = ListOps.Map(numbers, x => x.ToString());
int sumOfSquares = ListOps.Fold(numbers, 0, (acc, x) => acc + b * b);
На мой взгляд, ListOps<someType>
громоздкий и неуклюжий.Определение класса vanilla немного больше, но клиентский код легче читать - благодаря выводу типа.
В худшем случае C # не может определить типы, и вы должны указать их вручную.Вы бы предпочли написать ListOps<A>.Map<B>(...)
или ListOps.Map<A, B>(...)
?Я предпочитаю последнее.
Приведенная выше стратегия особенно хорошо работает, когда ваш статический класс содержит нет изменяемого состояния или его изменяемое состояние известно во время компиляции .
Если статический класс содержит изменяемое состояние, тип которого не определен во время компиляции, то, вероятно, у вас есть сценарий использования статического класса с общими параметрами.Надеюсь, что таких случаев немного, но когда это произойдет, вы будете рады, что C # поддерживает эту функциональность.