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;
}
}
Apakah ini salah? Saya akan berasumsi bahwa ini sebenarnya memiliki static readonly
bidang untuk setiap kemungkinan EnumRouteConstraint<T>
yang kebetulan saya contoh.
Jawaban:
Tidak masalah untuk memiliki bidang statis dalam tipe generik, selama Anda tahu bahwa Anda benar-benar akan mendapatkan satu bidang per kombinasi argumen tipe. Dugaan saya adalah bahwa R # hanya memperingatkan Anda jika Anda tidak menyadarinya.
Berikut ini contohnya:
Seperti yang Anda lihat,
Generic<string>.Foo
adalah bidang yang berbeda dariGeneric<object>.Foo
- mereka memegang nilai yang terpisah.sumber
class BaseFoo
mengandung anggota statis, maka berasal dari ituclass Foo<T>: BaseFoo
semuaFoo<T>
kelas akan berbagi nilai anggota statis yang sama?Dari wiki JetBrains :
sumber
Ini tidak selalu merupakan kesalahan - ini memperingatkan Anda tentang kesalahpahaman potensial dari C # generics.
Cara termudah untuk mengingat apa yang dilakukan generik adalah sebagai berikut: Generik adalah "cetak biru" untuk membuat kelas, seperti halnya kelas adalah "cetak biru" untuk membuat objek. (Yah, ini adalah penyederhanaan. Anda dapat menggunakan metode generik juga.)
Dari sudut pandang
MyClassRecipe<T>
ini bukan kelas - itu adalah resep, cetak biru, seperti apa kelas Anda nantinya. Setelah Anda mengganti T dengan sesuatu yang konkret, katakan int, string, dll., Anda mendapatkan kelas. Adalah sah untuk memiliki anggota statis (bidang, properti, metode) yang dideklarasikan di kelas Anda yang baru dibuat (seperti di kelas lain) dan tidak ada tanda kesalahan apa pun di sini. Akan terlihat mencurigakan, pada pandangan pertama, jika Anda mendeklarasikanstatic MyStaticProperty<T> Property { get; set; }
dalam cetak biru kelas Anda, tetapi ini juga legal. Properti Anda akan menjadi parameter, atau juga templated.Tidak heran dalam statika VB disebut
shared
. Namun dalam hal ini, Anda harus menyadari bahwa anggota yang "dibagikan" tersebut hanya dibagikan di antara instance dari kelas yang sama persis, dan tidak di antara kelas berbeda yang dihasilkan dengan mengganti<T>
dengan yang lain.sumber
Sudah ada beberapa jawaban bagus di sini, yang menjelaskan peringatan dan alasannya. Beberapa dari keadaan ini seperti memiliki medan statis dalam tipe generik umumnya kesalahan .
Saya pikir saya akan menambahkan contoh bagaimana fitur ini dapat berguna, yaitu kasus di mana menekan peringatan R # masuk akal.
Bayangkan Anda memiliki seperangkat kelas entitas yang ingin Anda buat bersambung, katakanlah ke Xml. Anda dapat membuat serializer untuk penggunaan ini
new XmlSerializerFactory().CreateSerializer(typeof(SomeClass))
, tetapi kemudian Anda harus membuat serializer terpisah untuk setiap jenis. Menggunakan generik, Anda bisa menggantinya dengan yang berikut ini, yang bisa Anda tempatkan di kelas generik tempat entitas dapat berasal:Karena Anda mungkin tidak ingin membuat serializer baru setiap kali Anda perlu membuat cerita bersambung dari jenis tertentu, Anda dapat menambahkan ini:
Jika kelas ini TIDAK generik, maka setiap instance dari kelas akan menggunakan yang sama
_typeSpecificSerializer
.Karena IS generik, satu set instance dengan tipe yang sama untuk
T
akan membagikan satu instance_typeSpecificSerializer
(yang akan dibuat untuk tipe spesifik itu), sedangkan instance dengan tipe berbeda untukT
akan menggunakan instance berbeda dari_typeSpecificSerializer
.Sebuah contoh
Asalkan dua kelas yang memperpanjang
SerializableEntity<T>
:... mari kita gunakan:
Dalam hal ini, di bawah tenda,
firstInst
dansecondInst
akan menjadi instance dari kelas yang sama (yaituSerializableEntity<MyFirstEntity>
), dan dengan demikian, mereka akan berbagi instance dari_typeSpecificSerializer
.thirdInst
danfourthInst
merupakan instance dari kelas yang berbeda (SerializableEntity<OtherEntity>
), dan juga akan berbagi contoh_typeSpecificSerializer
yang berbeda dari dua lainnya.Ini berarti Anda mendapatkan instans serializer yang berbeda untuk masing-masing jenis entitas Anda , sambil tetap membuatnya statis dalam konteks masing-masing jenis aktual (yaitu, dibagikan di antara instance yang dari jenis tertentu).
sumber