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;
}
}
Ist das falsch? Ich würde annehmen, dass dies tatsächlich ein static readonly
Feld für jede der möglichen EnumRouteConstraint<T>
Instanzen hat, die ich gerade habe.
Antworten:
Es ist in Ordnung, ein statisches Feld in einem generischen Typ zu haben, solange Sie wissen, dass Sie wirklich ein Feld pro Kombination von Typargumenten erhalten. Ich vermute, dass R # Sie nur warnt, falls Sie sich dessen nicht bewusst waren.
Hier ist ein Beispiel dafür:
Wie Sie sehen können,
Generic<string>.Foo
ist ein anderes Feld alsGeneric<object>.Foo
- sie enthalten separate Werte.quelle
class BaseFoo
ein statisches Element mit einem statischen Element erstelle ,class Foo<T>: BaseFoo
haben alleFoo<T>
Klassen denselben statischen Elementwert?Aus dem JetBrains-Wiki :
quelle
Dies ist nicht unbedingt ein Fehler - es warnt Sie vor einem möglichen Missverständnis von C # -Generika.
Der einfachste Weg, sich daran zu erinnern, was Generika tun, ist der folgende: Generika sind "Blaupausen" zum Erstellen von Klassen, ähnlich wie Klassen "Blaupausen" zum Erstellen von Objekten sind. (Nun, dies ist jedoch eine Vereinfachung. Sie können auch Methodengenerika verwenden.)
Aus dieser Sicht
MyClassRecipe<T>
ist es keine Klasse - es ist ein Rezept, eine Blaupause dafür, wie Ihre Klasse aussehen würde. Sobald Sie T durch etwas Konkretes ersetzen, z. B. int, string usw., erhalten Sie eine Klasse. Es ist völlig legal, ein statisches Element (Feld, Eigenschaft, Methode) in Ihrer neu erstellten Klasse (wie in jeder anderen Klasse) deklariert zu haben, und hier gibt es keine Anzeichen für einen Fehler. Es wäre auf den ersten Blick etwas verdächtig, wenn Sie erklärenstatic MyStaticProperty<T> Property { get; set; }
innerhalb Ihrer Klassenplanung , aber dies ist auch legal. Ihre Immobilie wird ebenfalls parametrisiert oder als Vorlage verwendet.Kein Wunder, dass in der VB-Statik aufgerufen wird
shared
. In diesem Fall sollten Sie sich jedoch bewusst sein, dass solche "gemeinsam genutzten" Mitglieder nur von Instanzen derselben exakten Klasse gemeinsam genutzt werden und nicht von den verschiedenen Klassen, die durch Ersetzen<T>
durch etwas anderes erzeugt werden.quelle
Hier gibt es bereits einige gute Antworten, die die Warnung und den Grund dafür erklären. Einige von diesen geben an, dass ein statisches Feld in einem generischen Typ im Allgemeinen ein Fehler ist .
Ich dachte, ich würde ein Beispiel hinzufügen, wie diese Funktion nützlich sein kann, dh ein Fall, in dem das Unterdrücken der R # -Warnung sinnvoll ist.
Stellen Sie sich vor, Sie haben eine Reihe von Entitätsklassen, die Sie serialisieren möchten, beispielsweise Xml. Sie können hierfür einen Serializer erstellen
new XmlSerializerFactory().CreateSerializer(typeof(SomeClass))
, müssen dann jedoch für jeden Typ einen eigenen Serializer erstellen. Mithilfe von Generika können Sie dies durch Folgendes ersetzen, das Sie in eine generische Klasse einfügen können, von der Entitäten abgeleitet werden können:Da Sie wahrscheinlich nicht jedes Mal einen neuen Serializer generieren möchten, wenn Sie eine Instanz eines bestimmten Typs serialisieren müssen, können Sie Folgendes hinzufügen:
Wenn diese Klasse NICHT generisch wäre, würde jede Instanz der Klasse dieselbe verwenden
_typeSpecificSerializer
.Da es jedoch generisch ist, wird eine Reihe von Instanzen mit demselben Typ für
T
eine einzelne Instanz von_typeSpecificSerializer
(die für diesen bestimmten Typ erstellt wurde) gemeinsam nutzen, während Instanzen mit einem anderen Typ fürT
unterschiedliche Instanzen von verwenden_typeSpecificSerializer
.Ein Beispiel
Vorausgesetzt, die zwei Klassen, die sich erweitern
SerializableEntity<T>
:... lass sie uns benutzen:
In diesem Fall wird unter der Haube,
firstInst
undsecondInst
werden Instanzen derselben Klasse (nämlich seinSerializableEntity<MyFirstEntity>
), und als solche werden sie eine Instanz teilen_typeSpecificSerializer
.thirdInst
undfourthInst
sind Instanzen einer anderen Klasse (SerializableEntity<OtherEntity>
), und so wird eine Instanz teilen von_typeSpecificSerializer
das ist verschieden von den anderen beiden.Das heißt , Sie verschiedene Serializer-Instanzen für jede Ihrer Einheit erhalten Typen , während sie noch statisch im Rahmen des jeweiligen Ist - Typs (dh gemeinsam von den Instanzen , die von einem bestimmten Typ sind) zu halten.
quelle