Öznitelikler C # 'a dinamik olarak eklenebilir mi?


143

Çalışma zamanında öznitelik eklemek veya çalışma zamanında özniteliğin değerini değiştirmek mümkün müdür?

Yanıtlar:


67

Öznitelikler statik meta verilerdir. Montajlar, modüller, türler, üyeler, parametreler ve dönüş değerleri C # 'da birinci sınıf nesneler değildir (örneğin, System.Typesınıf yalnızca bir türün yansıtılmış bir temsilidir). Bir tür için özniteliğin bir örneğini alabilir ve yazılabilirlerse özellikleri değiştirebilir, ancak bu, türe uygulandıkça özniteliği etkilemez.


68

Bu gerçekten tam olarak neyi başarmaya çalıştığınıza bağlıdır.

System.ComponentModel.TypeDescriptor şeyler türleri, özellikleri ve nesne örneklerine özelliklerini eklemek için kullanılır, ve bunu yanı sıra bu özellikleri almak için kullanmak zorunda olduğu sınırlaması vardır edilebilir. Bu nitelikleri tüketen kodu yazıyorsanız ve bu sınırlamalar dahilinde yaşayabiliyorsanız, kesinlikle öneririm.

Bildiğim kadarıyla, PropertyGrid denetimi ve visual studio tasarım yüzeyi BCL'de TypeDescriptor öğelerini tüketen tek şey. Aslında, gerçekten yapmaları gereken şeylerin yaklaşık yarısını böyle yapıyorlar.


7
Aslında, çoğu veri bağlama kullanımı TypeDescriptor- sadece değil PropertyGrid.
Marc Gravell

1
Silverlight projesine özellik meta meta özellikleri eklemek için herhangi bir çözüm (nerede TypeDescriptorve TypeDescriptionProvideruygulanmadı?)
Shimmy Weitzhandler

1
Dikkat edilmesi gereken, TypeDescriptor.GetAttributes () yinelenen öznitelikleri işlemez. Yalnızca özellik türünün sonuncusunu seçer. [Attr(1), Attr(2), Attr(3)]Sadece ex Attr(3)bulunur.
ohmusama

11

Yapamazsın. Bir geçici çözüm, çalışma zamanında türetilmiş bir sınıf oluşturmak ve özniteliği eklemek olabilir, ancak bu büyük olasılıkla aşırı bir bitliktir.


10

Sadece farklı olmak için, Reflection kullanarak referans veren bir makale buldum.

İşte bağlantı: http://www.codeproject.com/KB/cs/dotnetattributes.aspx , olası yaklaşımlar tartışıldığı için makalenin altındaki yorumlardan bazılarına da bakmak isteyeceksiniz.


10
Reflection.Emit sınıflarıyla çalışma zamanında öznitelikler oluşturabileceğinizi unutmayın, ancak bunları Emit paketi ile oluşturduğunuz sınıflara değil mevcut sınıflara bağlayabilirsiniz.
Panos

ne işe yaramaz bir cevap =)) hepimiz dinamik sınıfları değil, mevcut sınıfları önemsiyoruz.
Umutsuz

@Hopeless, alt sınıflara YourClassgirebilirsiniz YourRuntimeClassWithAttributes.
Motes

@Motes ne demek istediğinizden emin değil, sınıflarım önceden tanımlanmış, yani tüm temel sınıflar (sınıflarımı devralan) da önceden tanımlanmalı / belirlenmelidir. Reflection.Emit kullanarak dinamik olarak oluşturulmuş bir şeyle ilgilenmesinin herhangi bir yolunu düşünemiyorum.
Umutsuz

1
@Hopeless, mevcut bir sınıfa dinamik olarak nitelikler eklemek YourClassisterseniz, çalışma zamanında alt sınıfa sınıflandırabilir ve istenen dinamik olarak oluşturulmuş niteliklere sahip olan biraz farklı bir adla özdeş bir sınıf oluşturabilirsiniz ve polimorfizm, tip kontrol kodunun hala tanımlanmasına izin verir .
Motes

4

Hayır değil.

Öznitelikler meta verilerdir ve derlenmiş derlemede ikili biçimde depolanır (bu nedenle bunlarda yalnızca basit türleri kullanabilirsiniz).


3

Ben inanmıyorum. Yanlış olsam bile, umabileceğiniz en iyi şey onları asla bir Type örneğine eklemektir .


22
TypeDescriptor.AddAttributes (Object, Attribute []), hedef bileşen örneğine sınıf düzeyinde nitelikler ekler.
Peter Wone

3

Dinamik olarak eklenebilmek için bir şeye ihtiyacınız varsa, c # öznitelikleri böyle değildir. Verileri xml'de depolamaya bakın. Son zamanlarda w / öznitelikleri başladı, ancak sonunda w / xml serileştirme taşındı bir proje yaptım.


1
belki de güzel bir yol değildir, ancak diğer birçok kütüphanenin kullanmayı seçtiği ve bu kütüphanelerin davranışlarını özelleştirmek için yansıma =) ile oynamak gibi bir gereksinimimiz var.
Umutsuz

3

Neden ihtiyacın var? Nitelikler yansıma için ek bilgi verir, ancak dışarıdan istediğiniz özellikleri biliyorsanız, bunlara ihtiyacınız yoktur.

Meta verileri harici olarak nispeten kolay bir şekilde bir veritabanında veya kaynak dosyasında depolayabilirsiniz.


1
Kaynatma plakası ortadan kaldırılması. Bir sınıfın sınıf içindeki koda dayalı olarak otomatik olarak öznitelikler oluşturabilmesi kullanışlı olmaz mıydı? Ben SQL CLR nesnelerdeki boilerplate azaltmak için böyle bir şey anlamaya çalışıyorum. Diğer dillerde kolay olurdu ... bkz. Paulgraham.com/avg.html
Duncan Bayne

1

System.ComponentModel.TypeDescriptor ile çok zor denedim. Bu işe yaramaz anlamına gelmez ama bunun için kod görmek istiyorum.

Karşı bölümde, bazı Öznitelik değerlerini değiştirmek istedim. Bu amaçla iyi çalışan 2 işlev yaptım.

        // ************************************************************************
        public static void SetObjectPropertyDescription(this Type typeOfObject, string propertyName,  string description)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("description", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, description);
                }
            }
        }

        // ************************************************************************
        public static void SetPropertyAttributReadOnly(this Type typeOfObject, string propertyName, bool isReadOnly)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, isReadOnly);
                }
            }
        }

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.