C # genel öznitelik türlerini neden yasaklıyor?


510

Bu, derleme zamanı özel durumuna neden olur:

public sealed class ValidatesAttribute<T> : Attribute
{

}

[Validates<string>]
public static class StringValidation
{

}

C # genel öznitelikleri desteklemediğini anlıyorum. Ancak, çok fazla Google'dan sonra nedenini bulamıyorum.

Jenerik tiplerin neden türetilemeyeceğini bilen var mı Attribute? Herhangi bir teori var mı?


17
Yapabilirsin [Validates (typeof (string)] - Jeneriklerin daha güzel olacağını kabul ediyorum ...
ConsultUtah

20
Bu bu soruya çok geç ektir olsa da, sadece bu gibi kendilerini hem de allwed değildir (besbelli zaten nitelikleri olarak başlatılamaz) soyut nitelik sınıfları niteliklerini üzücü: abstract class Base<T>: Attribute {}olmayan oluşturmak için kullanılabilecek olan böyle genel türetilmiş sınıflar:class Concrete: Base<MyType> {}
Lucero

88
Lambdaları kabul eden genel özellikler ve özellikler için can atıyorum. [DependsOnProperty<Foo>(f => f.Bar)]Ya gibi şeyler düşünün [ForeignKey<Foo>(f => f.IdBar)]...
Jacek Gorgoń

3
Bu, yeni karşılaştığım bir durumda son derece yararlı olacaktır; genel bir türü kabul eden ve bu türü belirtilen gerçek değere zorlayan bir LinkedValueAttribute oluşturmak iyi olurdu. Bu numaralandırma değeri seçilirse kullanılması gereken başka bir numaralandırma "varsayılan" değerini belirtmek için numaralandırmalar için kullanabilirsiniz. Bu özniteliklerden birden fazlası farklı türler için belirtilebilir ve ihtiyacım olan türe göre ihtiyacım olan değeri alabilirim. Tür ve Nesne kullanmak için ayarlayabilirsiniz, ancak güçlü yazılan büyük bir artı olacaktır.
KeithS

10
Küçük bir IL umursamıyorsanız, bu umut verici görünüyor .
Jarrod Dixon

Yanıtlar:


358

Eh, müsait değil neden cevap veremez ama olabilir bir CLI sorun değil emin olun. CLI spesifikasyonu bundan bahsetmiyor (görebildiğim kadarıyla) ve IL'yi doğrudan kullanırsanız genel bir özellik oluşturabilirsiniz. C # 3 spesifikasyonunun onu yasaklayan kısmı - bölüm 10.1.4 "Sınıf tabanı spesifikasyonu" herhangi bir gerekçe vermiyor.

Ek açıklamalı ECMA C # 2 spesifikasyonu, izin verilmeyenlere bir örnek sunmasına rağmen yararlı bilgiler vermez.

Açıklamalı C # 3 spec kopyam yarın gelmeli ... Bunun daha fazla bilgi verip vermediğini göreceğim. Her neyse, kesinlikle bir çalışma zamanı yerine bir dil kararı.

DÜZENLEME: Eric Lippert'in cevabı (başka sözcüklerle yazılmış): Çok fazla değer katmayan bir kullanım durumu için hem dilde hem de derleyicide karmaşıklıktan kaçınmak için özel bir neden yoktur.


139
"hem dil hem de derleyicide karmaşıklığı önlemek dışında" ... ve bize ortak ve
çelişki

254
"fazla değer katmayan durum kullan"? Bu öznel bir görüş, bana çok değer katabilir!
Jon Kruger

34
Bu özelliğe sahip olmamam beni en çok üzen şey [PropertyReference (x => x.SomeProperty)] gibi şeyler yapamamak. Bunun yerine, bir çeşit berbat olduğunu düşündüğüm sihirli dizelere ve typeof () ihtiyacınız var.
Asbjørn Ulsberg

13
@John: Sanırım yeni bir dil özelliği tasarlama, belirleme, uygulama ve test etme maliyetini büyük ölçüde küçümsüyorsunuz.
Jon Skeet

14
Sadece @ Timwi'nin savunmasını eklemek istiyorum, burası tartışıldıkları tek yer değil ve bu soruya 13K görüşleri sağlıklı bir ilgi düzeyi anlamına geliyor. Ayrıca: yetkili bir cevap aldığınız için teşekkürler, Jon.
Jordan Gray

84

Bir öznitelik, derleme zamanında bir sınıfı süslerse de, genel bir sınıf çalışma zamanına kadar son tür bilgilerini almaz. Öznitelik derlemeyi etkileyebileceğinden, derleme zamanında "tam" olmalıdır.

Daha fazla bilgi için bu MSDN makalesine bakın .


3
Makale, mümkün olmadıklarını, ancak sebepsiz olduklarını göstermektedir. Cevabınızı kavramsal olarak anlıyorum. Konuyla ilgili daha resmi belgeler biliyor musunuz?
Bryan Watts

2
Makale, IL'nin çalışma zamanında gerçek türle değiştirilen jenerik yer tutucuları içerdiği gerçeğini kapsamaktadır. Gerisi benim tarafımdan çıkarıldı ... :)
GalacticCowboy

1
Değeri ne olursa olsun, VB aynı kısıtlamayı uygular: "Genel olan veya genel türde bulunan sınıflar bir öznitelik sınıfından miras alınamaz."
GalacticCowboy

1
ECMA-334, bölüm 14.16, "Aşağıda listelenen bağlamlarda sabit ifadeler gereklidir ve bu, gramer ifadesinde sabit ifade kullanılarak belirtilir.Bu bağlamlarda, bir ifade derlemede tam olarak değerlendirilemezse, derleme zamanı hatası oluşur. zaman." Nitelikler listede.
GalacticCowboy

4
Bu, IL'nin izin vereceğini belirten başka bir cevapla çelişiyor gibi görünüyor. ( stackoverflow.com/a/294259/3195477 )
UuDdLrLrSs

22

Neden izin verilmediğini bilmiyorum, ama bu olası bir çözüm

[AttributeUsage(AttributeTargets.Class)]
public class ClassDescriptionAttribute : Attribute
{
    public ClassDescriptionAttribute(Type KeyDataType)
    {
        _KeyDataType = KeyDataType;
    }

    public Type KeyDataType
    {
        get { return _KeyDataType; }
    }
    private Type _KeyDataType;
}


[ClassDescriptionAttribute(typeof(string))]
class Program
{
    ....
}

3
Ne yazık ki, niteliği tüketirken derleme zamanı yazmayı kaybedersiniz. Özniteliğin genel türde bir şey yarattığını düşünün. Etrafında çalışabilirsiniz, ama güzel olurdu; varyans gibi şu anda yapamayacağınız sezgisel şeylerden biri (şu anda).
Bryan Watts

14
Ne yazık ki bunu yapmamaya çalışıyorum, bu yüzden SO sorusunu buldum. Sanırım sadece typeof ile uğraşmak zorunda kalacağım. Jenerikler çok uzun bir süre var olduktan sonra ilke gerçekten kirli bir anahtar kelime hissediyor.
Chris Marisic

13

Bu gerçekten genel değildir ve yine de tür başına belirli bir öznitelik sınıfı yazmanız gerekir, ancak biraz savunmacı olarak kodlamak, aksi halde gerekenden daha az kod yazmak, polimorfizmden faydalanmak vb. İçin genel bir taban arabirimi kullanabilirsiniz.

//an interface which means it can't have its own implementation. 
//You might need to use extension methods on this interface for that.
public interface ValidatesAttribute<T>
{
    T Value { get; } //or whatever that is
    bool IsValid { get; } //etc
}

public class ValidatesStringAttribute : Attribute, ValidatesAttribute<string>
{
    //...
}
public class ValidatesIntAttribute : Attribute, ValidatesAttribute<int>
{
    //...
}

[ValidatesString]
public static class StringValidation
{

}
[ValidatesInt]
public static class IntValidation
{

}

8

Bu çok iyi bir soru. Özelliklere sahip Tecrübelerime göre, ben bir özelliğin üzerine yansıtan zaman mümkün olan bütün tip permütasyon için kontrol etmesi gerekir hangi bir koşul oluşturacak çünkü kısıt yerinde olduğunu düşünüyorum: typeof(Validates<string>), typeof(Validates<SomeCustomType>), vs ...

Kanımca, türe bağlı olarak özel bir doğrulama gerekiyorsa, bir özellik en iyi yaklaşım olmayabilir.

Belki bir SomeCustomValidationDelegateveya ISomeCustomValidatora parametresini alan bir doğrulama sınıfı daha iyi bir yaklaşım olabilir.


Size katılıyorum. Bu soruyu uzun zamandır soruyorum ve şu anda bir doğrulama sistemi inşa ediyorum. Şu anki terminolojimi soruyu sormak için kullandım, ancak bu mekanizmaya dayanan bir yaklaşım uygulamak gibi bir niyetim yok.
Bryan Watts

Aynı amaç için bir tasarım üzerinde çalışırken tökezledim: doğrulama. Ben otomatik olarak analiz etmek kolay bir şekilde yapmaya çalışıyorum (yani, onay için uygulamada doğrulama açıklayan bir rapor oluşturabilir) ve kod görselleştirme bir insan. Öznitelikler değilse, en iyi çözümün ne olacağından emin değilim ... Öznitelik tasarımını yine de deneyebilirim, ancak el ile türe özgü öznitelikleri bildirebilirim. Biraz daha fazla iş, ancak amaç doğrulama kurallarını bilmenin güvenilirliği (ve onay için bunları raporlayabilmektir).
bambamlar

4
jenerik tip tanımlarına karşı kontrol edebilirsiniz (örn. typeof (Validates <>)) ...
Melvyn

5

Bu şu anda bir C # dili özelliği değil, ancak resmi C # dili repo hakkında çok fazla tartışma var .

Gönderen bazı toplantı notları :

Her ne kadar bu prensipte çalışsa da, çalışma zamanının çoğu versiyonunda hatalar vardır, böylece düzgün çalışmaz (asla egzersiz yapılmadı).

Hangi hedef çalışma zamanının üzerinde çalıştığını anlamak için bir mekanizmaya ihtiyacımız var. Birçok şey için buna ihtiyacımız var ve şu anda buna bakıyoruz. O zamana kadar kabul edemeyiz.

Büyük bir C # sürümü için aday, eğer yeterli sayıda çalışma zamanı sürümü ile başa çıkabilirsek.


1

Benim geçici çözüm şöyle bir şey:

public class DistinctType1IdValidation : ValidationAttribute
{
    private readonly DistinctValidator<Type1> validator;

    public DistinctIdValidation()
    {
        validator = new DistinctValidator<Type1>(x=>x.Id);
    }

    public override bool IsValid(object value)
    {
        return validator.IsValid(value);
    }
}

public class DistinctType2NameValidation : ValidationAttribute
{
    private readonly DistinctValidator<Type2> validator;

    public DistinctType2NameValidation()
    {
        validator = new DistinctValidator<Type2>(x=>x.Name);
    }

    public override bool IsValid(object value)
    {
        return validator.IsValid(value);
    }
}

...
[DataMember, DistinctType1IdValidation ]
public Type1[] Items { get; set; }

[DataMember, DistinctType2NameValidation ]
public Type2[] Items { get; set; }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.