public class EnumRouteConstraint<T> : IRouteConstraint
where T : struct
{
private static readonly Lazy<HashSet<string>> _enumNames; // <--
static EnumRouteConstraint()
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException(
Resources.Error.EnumRouteConstraint.FormatWith(typeof(T).FullName));
}
string[] names = Enum.GetNames(typeof(T));
_enumNames = new Lazy<HashSet<string>>(() => new HashSet<string>
(
names.Select(name => name), StringComparer.InvariantCultureIgnoreCase
));
}
public bool Match(HttpContextBase httpContext, Route route,
string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
bool match = _enumNames.Value.Contains(values[parameterName].ToString());
return match;
}
}
Это неправильно? Я хотел бы предположить, что это на самом деле имеет static readonly
поле для каждого из возможных EnumRouteConstraint<T>
случаев, которые я случайно произвел.
Ответы:
Хорошо иметь статическое поле в универсальном типе, если вы знаете, что вы действительно получите одно поле на комбинацию аргументов типа. Я думаю, что R # просто предупреждает вас, если вы не знали об этом.
Вот пример этого:
Как видите,
Generic<string>.Foo
поле отличается отGeneric<object>.Foo
- они содержат отдельные значения.источник
class BaseFoo
содержащий статический член, то получим ли из негоclass Foo<T>: BaseFoo
всеFoo<T>
классы одинаковое значение статического члена?Из вики JetBrains :
источник
Это не обязательно ошибка - это предупреждение о возможном недопонимании обобщений C #.
Самый простой способ запомнить, что делают дженерики, это следующее: дженерики - это «чертежи» для создания классов, так же как классы являются «чертежами» для создания объектов. (Ну, это упрощение. Вы также можете использовать обобщенные методы).
С этой точки зрения
MyClassRecipe<T>
это не класс, это рецепт, план того, как будет выглядеть ваш класс. Как только вы замените T чем-то конкретным, скажем, int, string и т. Д., Вы получите класс. Вполне допустимо, чтобы статический член (поле, свойство, метод) был объявлен во вновь созданном классе (как и в любом другом классе), и здесь не было никаких признаков какой-либо ошибки. На первый взгляд, было бы несколько подозрительно, если бы вы объявили вstatic MyStaticProperty<T> Property { get; set; }
рамках своего класса, но это тоже законно. Ваша собственность будет параметризована или шаблонизирована.Недаром в VB статики называются
shared
. В этом случае, однако, вы должны знать, что такие «общие» члены разделяются только между экземплярами одного и того же класса, а не между отдельными классами, полученными путем замены<T>
чем-то другим.источник
Здесь уже есть несколько хороших ответов, которые объясняют предупреждение и причину его возникновения. Некоторые из них указывают на то, что статическое поле общего типа обычно является ошибкой .
Я думал, что добавлю пример того, как эта функция может быть полезна, то есть случай, когда подавление предупреждения R # имеет смысл.
Представьте, что у вас есть набор классов сущностей, которые вы хотите сериализовать, скажем, в Xml. Для этого вы можете создать сериализатор
new XmlSerializerFactory().CreateSerializer(typeof(SomeClass))
, но тогда вам придется создать отдельный сериализатор для каждого типа. Используя дженерики, вы можете заменить их следующим, который вы можете поместить в дженерик-класс, из которого могут быть получены объекты:Поскольку вы, вероятно, не хотите генерировать новый сериализатор каждый раз, когда вам нужно сериализовать экземпляр определенного типа, вы можете добавить это:
Если этот класс НЕ является универсальным, то каждый экземпляр класса будет использовать то же самое
_typeSpecificSerializer
.Однако, поскольку он универсален, набор экземпляров с одинаковым типом for
T
будет использовать один экземпляр_typeSpecificSerializer
(который будет создан для этого конкретного типа), а экземпляры с другим типом forT
будут использовать разные экземпляры_typeSpecificSerializer
.Пример
Предусмотрено два класса, которые расширяются
SerializableEntity<T>
:... давайте использовать их:
В этом случае под капотом
firstInst
иsecondInst
будут экземпляры одного класса (а именноSerializableEntity<MyFirstEntity>
), и как таковые они будут совместно использовать экземпляр_typeSpecificSerializer
.thirdInst
иfourthInst
являются экземплярами другого класса (SerializableEntity<OtherEntity>
), и поэтому будут использовать экземпляр,_typeSpecificSerializer
который отличается от двух других.Это означает, что вы получаете разные экземпляры сериализатора для каждого из ваших типов сущностей , сохраняя при этом их статичность в контексте каждого фактического типа (т. Е. Разделяемые между экземплярами определенного типа).
источник