ReSharper ostrzega: "pole statyczne w typie generycznym"
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;
}
}
Czy to źle? Zakładam, że to rzeczywiście ma pole static readonly
dla każdego z możliwych EnumRouteConstraint<T>
, które zdarza mi się wystosować. 4 answers
Dobrze jest mieć statyczne pole w typie ogólnym, o ile wiesz, że naprawdę dostaniesz jedno pole na kombinację argumentów typu. Zgaduję, że R# ostrzega cię, gdybyś nie był tego świadomy.
Oto przykład:
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
}
}
Jak widać, Generic<string>.Foo
jest innym polem niż Generic<object>.Foo
- posiadają osobne wartości.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-02 10:51:40
Z JetBrains wiki :
W zdecydowanej większości przypadków, mając pole statyczne w typie ogólnym to oznaka błędu. Powodem tego jest to, że pole statyczne w Typ generyczny będzie , a nie współdzielony pomiędzy instancjami o różnych bliskich skonstruowane typy. Oznacza to, że dla klasy generycznej
C<T>
, która posiada pole StatyczneX
, wartościC<int>.X
iC<string>.X
mają zupełnie inne, niezależne wartości.W rzadkich przypadkach kiedy robisz potrzebujesz 'wyspecjalizowanych' pól statycznych, nie krępuj się tłumić Ostrzeżenia.
Jeśli chcesz mieć pole statyczne współdzielone między instancjami z różne argumenty generyczne, zdefiniuj nie-generyczną klasę bazową do przechowuj statyczne elementy, a następnie Ustaw typ generyczny na dziedziczenie od ten typ.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-12 10:13:01
To niekoniecznie błąd-ostrzega Cię o potencjale niezrozumienie C# generics.
Najprostszym sposobem na zapamiętanie tego, co robią leki generyczne, jest następujący sposób: Generyki są "schematami" do tworzenia klas, podobnie jak klasy są "schematami" do tworzenia obiektów. (Cóż, jest to jednak uproszczenie. Możesz również użyć metod generycznych.)
Z tego punktu widzenia {[0] } to nie jest klasa - to jest przepis, schemat, co twoja klasa na to wygląda. Po zastąpieniu T czymś konkretnym, powiedzmy int, string itp. masz zajęcia. Jest całkowicie legalne mieć statyczny element (pole, właściwość, metoda) zadeklarowany w nowo utworzonej klasie (jak w każdej innej klasie) i nie ma żadnych oznak błędu tutaj.
Na pierwszy rzut oka byłoby to podejrzane, gdybyś zadeklarował static MyStaticProperty<T> Property { get; set; }
w swoim schemacie klasowym, ale to też jest legalne. Twoja nieruchomość będzie również parametryzowana lub szablonowa.
Nic dziwnego, że w statyce VB nazywa się shared
. W tym przypadku powinieneś jednak mieć świadomość, że takie" wspólne " elementy są dzielone tylko pomiędzy instancjami tej samej klasy, a nie pomiędzy odrębnymi klasami powstałymi przez zastąpienie <T>
czymś innym.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-07 18:37:45
Jest tu już kilka dobrych odpowiedzi, które wyjaśniają Ostrzeżenie i powód. Kilka z nich stwierdza coś w rodzaju posiadanie statycznego pola w typie ogólnym ogólnie jest błędem .
Pomyślałem, że dodam przykład, jak ta funkcja może być przydatna, np. przypadek, w którym tłumienie Ostrzeżenia R#ma sens.
Wyobraź sobie, że masz zestaw klas encji, które chcesz serializować, powiedzmy do Xml. Możesz utworzyć do tego serializer używając new XmlSerializerFactory().CreateSerializer(typeof(SomeClass))
, ale następnie będziesz musiał utworzyć oddzielny serializer dla każdego typu. Używając generyków, możesz zastąpić je poniższą, którą możesz umieścić w klasie generycznej, z której mogą wywodzić się encje:
new XmlSerializerFactory().CreateSerializer(typeof(T))
Ponieważ prawdopodobnie nie chcesz generować nowego serializera za każdym razem, gdy musisz serializować wystąpienie określonego typu, możesz dodać to:
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);
}
}
Gdyby ta klasa nie była generyczna, wtedy każda instancja klasy używałaby tego samego _typeSpecificSerializer
.
Ponieważ jest generic jednak, zbiór wystąpień o tym samym typie dla T
będzie współdzielić jedną instancję _typeSpecificSerializer
(która zostanie utworzona dla tego konkretnego typu), podczas gdy wystąpienia o innym typie dla T
będą używać różnych wystąpień _typeSpecificSerializer
.
Przykład
Pod warunkiem, że dwie klasy rozszerzające 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; }
}
... użyjmy ich:
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();
W tym przypadku, pod maską, firstInst
i secondInst
będą instancjami tej samej klasy (mianowicie SerializableEntity<MyFirstEntity>
), a jako takie, będą dzielić instancję _typeSpecificSerializer
.
thirdInst
i fourthInst
są instancjami innej klasy (SerializableEntity<OtherEntity>
), a więc będą współdzielić instancję _typeSpecificSerializer
, która jest Inna od dwóch pozostałych.
Oznacza to, że otrzymujesz różne instancje serializera dla każdego z typów encji , zachowując je statyczne w kontekście każdego rzeczywistego typu (tj. współdzielone między instancjami danego typu).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-22 06:50:11