[C#] Пользовательские атрибуты сборки

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by Natali Osina, 7 Jul 2011.

  1. Natali Osina

    Natali Osina New Member

    Joined:
    15 Jun 2011
    Messages:
    65
    Likes Received:
    3
    Reputations:
    0
    Всем приветик)
    Я разобралась с встроенными атрибутами сборок.
    когда начала разбирать создание собственных атрибутов то все вроде бы хорошо, пока не пошла дальше одной сборки.
    так вот собственно что хочу узнать
    как собственноручно созданный атрибут в сборке 1 можно получить из сборки 2, причем референс не указывать, а только через рефлексию. что бы наперед не знать какие есть в каталоге сборки и с камими атрибутами.

    я пришла не с пустыми руками))
    вот то что я уже успела напрограммировать )

    СБОРКА ГЛАВНАЯ:

    PHP:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Reflection;
    using System.IO;

    [
    AttributeUsage(AttributeTargets.AllInherited falseAllowMultiple true)]
    public class 
    MyAttribute System.Attribute
    {
        private 
    string NAME;
        public 
    MyAttribute(string NAME)
        {
            
    this.NAME NAME;
        }
        public 
    virtual string STOKAatributa
        
    {
            
    get
            
    {
                return 
    NAME;
            }
        }
    }

    namespace 
    UserAttributeBetween2Assemblys
    {
        public 
    partial class Form1 Form
        
    {
            public 
    Form1()
            {
                
    InitializeComponent();
            }

            private 
    void button1_Click(object senderEventArgs e)
            {
                
    string folder System.AppDomain.CurrentDomain.BaseDirectory;
                
    string[] files Directory.GetFiles(folder"*.dll");
                foreach (
    string file in files)
                {
                    
    Assembly asm Assembly.LoadFile(file);
                    
    MyAttribute adAttr = (MyAttribute)Attribute.GetCustomAttribute(asmtypeof(MyAttribute));
                    
    MessageBox.Show(adAttr.STOKAatributa);
                }
            }
        }
    }

    и инфо о сборке

    PHP:
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;

    [
    assemblyMyAttribute("MAIN FORM")]
    и теперь сборка с которой хочу вытащить атрибут и вывести в главной программе.
    PHP:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    [
    AttributeUsage(AttributeTargets.AllInherited falseAllowMultiple true)]
    public class 
    MyAttribute System.Attribute
    {
        public  
    string NAME;
        public 
    MyAttribute(string NAME)
        {
            
    this.NAME NAME;
        }
        public 
    virtual string STOKAatributa
        
    {
            
    get
            
    {
                return 
    NAME;
            }
        }
    }

    namespace 
    sborka
    {
        public class 
    classOfSborka
        
    {

        }
    }
    и информация о этой сборке
    PHP:
    [assemblyMyAttribute("ТО ЧТО НУЖНО ВЫВЕСТИ В ГЛАВНОЙ ПРОГЕ")]
    и теперь подскажите мне пожалуйста почему не работает кусок кода

    MyAttribute adAttr = (MyAttribute)Attribute.GetCustomAttribute(asm, typeof(MyAttribute));


    подскажите как мне получить ту строчку.. я не знаю дальше что писать..
    спасибо)
     
  2. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Я правильно понял что в обоих сборках у вас определен один и тот же класс атрибута?
    Если в сборках Asm1 и Asm2 определены полностью идентичные классы с одинаковыми названиями и набором членов это не значит что это один и тот же класс. Т.е. привести Asm1.MyAttribute к Asm2.MyAttribute не получится. По-этому атрибут и не находится, т.к. ищет не тот тип.
    В общем случае получить список классов-атрибутов определенных в сборке можно так:
    Code:
                var attrs = Assembly.LoadFrom("foo.dll")
                    .GetTypes()
                    .Where(t => t.IsSubclassOf(typeof(Attribute)));
    
    Получить тип (System.Type) атрибута с заранее известным именем так:
    Code:
                var myAttr = Assembly.LoadFrom("foo.dll")
                    .GetTypes()
                    .Where(t => t.IsSubclassOf(typeof(Attribute)))
                    .FirstOrDefault( attr => attr.Name == "MyAttribute");
    Либо если упростить:
    Code:
                var myAttr = Assembly.LoadFrom("foo.dll")
                    .GetType("MyAttribute");
    И соответственно передавать в метод GetCustomAttribute полученный ранее тип.
    Чтобы получить "строчку" можно написать так:
    Code:
    string name = ((MyAttribute)Attribute.GetCustomAttribute(asm, myAttr)).STOKAatributa;
     
    #2 GhostOnline, 7 Jul 2011
    Last edited: 7 Jul 2011
  3. Natali Osina

    Natali Osina New Member

    Joined:
    15 Jun 2011
    Messages:
    65
    Likes Received:
    3
    Reputations:
    0
    ой спасибо большое сейчас попробую обязательно.
    при таком подходе как вы предложили мне не нужно теперь создавать такой же атрибут для главной сборки?
    так как он там в принципе не нужен совсем. :eek:
     
  4. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Нет, нужно всего лишь чтобы атрибут был пабличным, и знать его название, а далее вытягивать его тип с помощью reflection'a
     
  5. Natali Osina

    Natali Osina New Member

    Joined:
    15 Jun 2011
    Messages:
    65
    Likes Received:
    3
    Reputations:
    0
    не работает то что Вы предожили...
    смотрите почему.
    я с главной сборки которая читает, убрала атрибут, что бы его там небыло. ведь есть же сборки с разными атрибутами и на всех не напишешь наперед...
    так вот оставила только такой код

    PHP:
    private void button1_Click(object senderEventArgs e)
            {
                
    string folder System.AppDomain.CurrentDomain.BaseDirectory;
                
    string[] files Directory.GetFiles(folder"*.dll");
                foreach (
    string file in files)
                {
                    
    Assembly asm Assembly.LoadFile(file);
                    var 
    myAttr Assembly.LoadFrom(file).GetType("MyAttribute");
                    
    string name = ((MyAttribute)Attribute.GetCustomAttribute(asmmyAttr)).STOKAatributa;
    }

    ошибка в

    string name = ((MyAttribute)Attribute.GetCustomAttribute(asm, myAttr)).STOKAatributa;

    так как я убрала с этой (главной) сборки атрибут.
    атрибут остался только в сборке к которой подключаемся.
    в главной сборке только знаем что имя атрибута MyAttribute и все.
    ну я думаю по логике так же правильнее, чем писать для главной сборки еще раз такой же атрибут, только потому что это нужно для того что бы получить атрибут другой сборки...
    а такой вариант работать не будет так как в кусочке кода
    PHP:
    string name = ((MyAttribute)Attribute.GetCustomAttribute(asmmyAttr)).STOKAatributa;
    неизвестно что такое MyAttribute и STOKAatributa....
    я уже и сама запуталась что к чему...
    если этот атрибут использовать в сборке которую он и описует, то проблем нет.. и я тут сама разобралась.
    а для передачи атрибутов между сборками я не знаю что применить...
    помогите понять)
    спасибо.
     
    1 person likes this.
  6. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Также с помощью рефлексии, только нужно еще знать имя свойства:
    PHP:
    // загружаем сборку с именем file
    Assembly asm Assembly.LoadFile(file);
    // дважды загружать сборку кстати не нужно
    // получаем тип атрибута
    var myAttrType asm.GetType("MyAttribute");
    // тут понадобится получить объект атрибута
    var attrObj Attribute.GetCustomAttribute(asmmyAttrType);
    string name = (string)myAttrType.GetType().GetProperty("STOKAatributa").GetValue(attrObjnull);
     
    #6 GhostOnline, 8 Jul 2011
    Last edited: 8 Jul 2011
  7. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Вот полностью рабочий пример, только я не создавал свою сборку с атрибутом а просто взял системную. Но смысл остается прежним - я получил значение свойства атрибута внешней сборки:
    PHP:
            static void Main(string[] args)
            {
                
    // зашружаем сборку
                
    var asm Assembly.Load("mscorlib.dll");
                
    // получаем тип атрибута
                
    var attrType asm.GetType("System.CLSCompliantAttribute");
                
    // получаем экземпляр атрибута
                
    var attrObj Attribute.GetCustomAttribute(asmattrType);
                
    // заранее зная тип и имя свойства получаем его значение
                
    bool b = (bool) attrType.GetProperty("IsCompliant").GetValue(attrObjnull);
                
    Console.WriteLine(b);
            }
     
    1 person likes this.
  8. Natali Osina

    Natali Osina New Member

    Joined:
    15 Jun 2011
    Messages:
    65
    Likes Received:
    3
    Reputations:
    0
    Спасибо.
    Действительно так заработало.
    теперь сама разберусь глубже в коде что бы тема не прошла мимо)