ReSharper警告:“genericstypes的静态字段”

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>我碰巧实例。

在genericstypes中有一个静态字段是很好的,只要你知道每个types参数的组合都会得到一个字段。 我的猜测是,R#只是警告你,如果你不知道这一点。

这是一个例子:

 using System; public class Generic<T> { // Of course we wouldn't normally have public fields, but... public static int Foo; } public class Test { public static void Main() { Generic<string>.Foo = 20; Generic<object>.Foo = 10; Console.WriteLine(Generic<string>.Foo); // 20 } } 

正如你所看到的, Generic<string>.Foo是一个与Generic<object>.Foo不同的字段,它们拥有不同的值。

从JetBrains wiki :

在绝大多数情况下,在generics中使用静态字段是错误的标志。 原因是genericstypes的静态字段不会在不同的closures构造types的实例之间共享。 这意味着对于具有静态字段X的generics类C<T>C<int>.XC<string>.X值具有完全不同的独立值。

在极less数情况下,如果您确实需要“专业”静态字段,请随时取消警告。

如果需要在具有不同通用参数的实例之间共享静态字段,请定义一个非generics基类来存储静态成员,然后将genericstypes设置为从此typesinheritance。

这不是一个错误。 这是对C#中的generics的一种误解。 记住generics所做的最简单的方法如下:generics是创build类的“蓝图”,很像类是创build对象的“蓝图”。 (嗯,这是一个简化,你也可以使用方法generics。)

从这个angular度来看, MyClassRecipe<T>不是一个类,它是你的类看起来像一个配方,一个蓝图。 一旦你用具体的东西replaceT,比如说int,string等等,你会得到一个类。 在新创build的类中声明一个静态成员(字段,属性,方法)是完全合法的(如同在其他类中一样),并且在这里没有任何错误的迹象。 如果你声明static MyStaticProperty<T> Property { get; set; } static MyStaticProperty<T> Property { get; set; } static MyStaticProperty<T> Property { get; set; }在你的class级蓝图内,但这也是合法的。 只有你的财产将被参数化,或模板,以及。

难怪在VB静态被称为shared 。 然而,在这种情况下,您应该意识到,这些“共享”成员是在类的实例之间共享的,而不是通过用其他方式replace<T>而生成的不同类中的。

这里已经有好几个很好的答案了,解释了这个警告和原因。 其中的几个状态就像在generics中有一个静态字段通常是一个错误

我想我会添加一个这个function如何有用的例子,即抑制R# – 警告的情况是有道理的。

想象一下,你有一套你想要序列化的实体类,对Xml说。 您可以使用new XmlSerializerFactory().CreateSerializer(typeof(SomeClass))为此创build一个序列化程序,但是您将不得不为每个types创build一个单独的序列化程序。 使用generics,你可以用下面的代替,你可以把它放在一个实体可以派生出来的generics类中:

 new XmlSerializerFactory().CreateSerializer(typeof(T)) 

由于每次需要序列化特定types的实例时,您可能不希望生成新的序列化程序,因此可以添加以下内容:

 public class SerializableEntity<T> { // ReSharper disable once StaticMemberInGenericType private static XmlSerializer _typeSpecificSerializer; private static XmlSerializer TypeSpecificSerializer { get { // Only create an instance the first time. In practice, // that will mean once for each variation of T that is used, // as each will cause a new class to be created. if ((_typeSpecificSerializer == null)) { _typeSpecificSerializer = new XmlSerializerFactory().CreateSerializer(typeof(T)); } return _typeSpecificSerializer; } } public virtual string Serialize() { // .... prepare for serializing... // Access _typeSpecificSerializer via the property, // and call the Serialize method, which depends on // the specific type T of "this": TypeSpecificSerializer.Serialize(xmlWriter, this); } } 

如果这个类不是generics的,那么这个类的每个实例将使用相同的_typeSpecificSerializer

因为它是通用的,所以T一组实例将共享_typeSpecificSerializer的一个实例(将为该特定types创build),而具有不同types的实例将使用_typeSpecificSerializer不同实例。

一个例子

提供了扩展SerializableEntity<T>的两个类:

 // Note that T is MyFirstEntity public class MyFirstEntity : SerializableEntity<MyFirstEntity> { public string SomeValue { get; set; } } // Note that T is OtherEntity public class OtherEntity : SerializableEntity<OtherEntity > { public int OtherValue { get; set; } } 

…让我们使用它们:

 var firstInst = new MyFirstEntity{ SomeValue = "Foo" }; var secondInst = new MyFirstEntity{ SomeValue = "Bar" }; var thirdInst = new OtherEntity { OtherValue = 123 }; var fourthInst = new OtherEntity { OtherValue = 456 }; var xmlData1 = firstInst.Serialize(); var xmlData2 = secondInst.Serialize(); var xmlData3 = thirdInst.Serialize(); var xmlData4 = fourthInst.Serialize(); 

在这种情况下, firstInstsecondInst将是同一类的实例(即SerializableEntity<MyFirstEntity> ),因此它们将共享_typeSpecificSerializer一个实例。

thirdInstthirdInst是不同类( SerializableEntity<OtherEntity> )的实例,因此将共享与另外两个不同_typeSpecificSerializer实例。

这意味着你为每个实体types获得不同的序列化实例,同时仍然保持静态在每个实际types的上下文中(即,在特定types的实例之间共享)。