Как получить через пространство имён «рефлекшн» данные(методы) из сборки (Dll)?

Хэлп! Как получить через пространство имён «рефлекшн» данные (методы) из сборки? Не представляю как выглядят вытянутые из длл данные, как они отображаются?

Этот код я скомуниздил и вставил путь к моему длл файлу:
prntscr.com/61s80p

вот ещё пример кода который я могу использовать.
prntscr.com/61i2w0

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Подскажите теперь плиз как вытянуть методы с атрибутом «тест» ?

Подскажите пожалуйста как из сборки вытянуть вытянуть метод с атрибутом «тест» ?
prntscr.com/63pcg3

var myAssembly = Assembly.LoadFrom(@"D:\Tests.dll");
foreach (Type type in myAssembly.GetTypes())
{
    foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | 
                                               BindingFlags.Static |
                                               BindingFlags.Public |
                                               BindingFlags.NonPublic))
    {
        MessageBox.Show(field.Name + " - " + field.FieldType);
    }
}

Вам просто потрібно у циклі вставити 2 стрічки

 MethodAttributes attributes = method.Attributes;
SampleClass.findAttribute(typeof(System.Reflection.MethodAttributes), (int) attributes, method);
    public static void findAttribute(Type attribType, int iAttribValue, MethodBase method)
    {
        if (!attribType.IsEnum)
        { 
            Console.WriteLine("This type is not an enum."); 
            return; 
        }

        FieldInfo[] fields = attribType.GetFields(BindingFlags.Public | BindingFlags.Static);
        for (int i = 0; i < fields.Length; i++)
        {
            int fieldvalue = (Int32)fields[i].GetValue(null);
            if ("test" == fields[i].Name)
            {
                Console.WriteLine("test is here:"+method.Name);
            }
        }
    }

В .NET сборки кроме непосредственно IL-кода содержат метаданные, которые позволяют обращаться к классам, которые находятся в этой сборке, к методам, полям и свойствам этих классов. Собственно, с помощью рефлексии можно вытащить из сборки информацию о методе в виде класса System.Reflection.MethodInfo, а дальше уже можно увидеть все характеристики этого метода, вызвать его через Invoke и т.д. Отображать информацию из сборок можно как угодно, хоть в консоль выводи, хоть TreeView наполняй, это, как говорится, up to you :)
Пример кода на скорую руку:


class AssemblyDumper
  {
    private string _filePath;
    public AssemblyDumper(string filePath)
    {
      _filePath = filePath;
    }

    public void Dump(TextWriter textWriter)
    {
      Assembly asm = Assembly.LoadFile(_filePath);

      textWriter.WriteLine(asm.FullName);
      foreach (var type in asm.GetTypes())
      {
        textWriter.WriteLine(type.FullName);
        DumpMethods(textWriter, type, "\t");
      }
    }

    private void DumpMethods(TextWriter textWriter, Type type, string indent)
    {
      var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
      foreach (MethodInfo methodInfo in type.GetMethods(bindingFlags))
      {
        string methodParams = String.Join(", ", methodInfo.GetParameters().Select(p => String.Format("{0} {1}", p.ParameterType, <a href="http://p.Name" target="_blank">p.Name</a>)).ToArray());

        textWriter.WriteLine(String.Format("{0}{1}({2})", indent, <a href="http://methodInfo.Name" target="_blank">methodInfo.Name</a>, methodParams));
      }
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      var dumper = new AssemblyDumper(@"D:\Tests.dll");
      dumper.Dump(Console.Out);
    }
  }

С одной стороны осмысленная реализация visitor через передачу TextWriter — что как бы намекает, что человек не лох, а с другой, попсовейший string.format с примитивным шаблоном и LINQ оставляют смешенные чувства.

Для реализации Visitor не хватает обертки над TextWriter и базового класса/интерфейса, чтобы можно было подбросить другую реализацию, например, для заполнения дерева и т.д. Использование Visitor здесь вполне естественно, ведь структура сборки штука постоянная, но к вопросу топикстартера паттерны имеют весьма опосредованное отношение.
Если говорить о боевом коде, то я выделил бы интерфейсы и для визитора и для класса, который копается во внутренностях сборки через рефлексию, и инжектил бы туда визитор в конструкторе через IoC-контейнер. А здесь просто демонстрация, что в реализации лучше избавиться от жесткой зависимости от Console, вдруг в файлик захочется записать вывод, или еще чего.

Слово «попсовый» из-за его негативного оттенка довольно странно употреблять в контексте разработки, где читаемость кода превыше всего. Чем более простые и понятные большинству девелоперов конструкции ты используешь, тем меньше тебя будут проклинать потомки при блейме, с ненавистью глядя на твое имя напротив строчек кода с каким-то уникальным и экзотическим решением :)

String.Format, по моему мнению, лучше в конкатенации в плане читаемости, когда в строке появляются литералы:

p.ParameterType + "  " + p.Name
выглядит как-то по-уродски, не говоря уже о:
indent + methodInfo.Name + "(" + methodParams + ")"
Ну и пожелания по формату вывода настолько часто меняются, что лучше предусмотреть это сразу. StringBuilder в этом случае это явный overkill и читаемость у него хуже. Что до производительности, то компилятор в реальной жизни преобразует выражение с конкатенацией в String.Concat, так что теоретический аргумент о том, что при конкатенации создаются лишние временные объекты приводить не буду.

Что касается LINQ, то можно слегка упростить выражение, убрав ToArray(), ведь с 4-й версии фреймворка String.Join кроме массивов принимает IEnumerable.

string methodParams = String.Join(", ", 
    methodInfo.GetParameters().Select(p => String.Join(" ", p.ParameterType, p.Name)));

Ну и хотелось бы увидеть твои аргументированные предложения, что использовать вместо String.Format и LINQ.

1. только textWriter.Write(...); — и так один за одним, никакой конкатенации и string.format.

2. Для реального dev кода: отдельный метод который принимает TextWriter и массив параметров и засовывает в TextWriter имена параметров с типами через запятую последовательно в цикле без String.Join. Я к тому, что работа вроде не сложная, а тут столько промежуточных стрингов наплодится, что коллектор тригернётся на сборку. Но если для demo, то пожалуй и так сойдёт.
Я не против Linq и String.Format — любой на твоём месте так бы сделал, но не любой так зашарит заюзать TextWriter, вот и получается, что часть кода уровня милда, а подход уровня архитектора. Стили контрастируют. Если ты написал что-то типа Console.WriteLine — то и вопросов не было бы :).

Если принять вводную о том, что мы поковырялись профайлером, и увидели, что существует bottleneck в том месте, то согласен с последовательным TextWriter.Write(). Можно было бы и дальше оптимизировать, выделить буфер, а как заполнится сразу сбрасывать его на диск через WriteFile винапишный, еще быстрее было бы. Но тут надо измерять, а иначе premature optimization :)
А для основной массы кода я все-таки за использование как можно более выразительных конструкций, типа тех же форматных строк. Кстати, последний String.Fromat действительно лишний, можно было просто:

textWriter.WriteLine("{0}{1}({2})", indent, methodInfo.Name, methodParams);

Для человека который, задаёт вопрос об извлечении метаинформации методов, вот это

string methodParams = String.Join(", ", methodInfo.GetParameters().Select(p => String.Format("{0} {1}", p.ParameterType, p.Name)).ToArray());
тоже может оказаться не очень выразительно: типа однострочно, длинно, большая вложенность, лямбда. Я бы через цикл показывал. Eсли он ниже мидла, то ему для понимания всё равно пришлось это всё расписывать на бумаге по шагам.

надо перебрать экспортируемые методы из DLL?

Решение на скорую руку — выводит список типов и их методы (с указанием параметров).

static void Main(string[] args)
        {
            Assembly asm = Assembly.LoadFrom(@"D:\Tests.dll");
            Type[] types = asm.GetTypes();
            MethodInfo[][] methods = new MethodInfo[types.Length][];
            ParameterInfo[][][] methodParameters = new ParameterInfo[types.Length][][];

            for (int i = 0; i < types.Length; i++)
			{
			    Console.WriteLine(types[i].Name);

                methods[i] = types[i].GetMethods();
                methodParameters[i] = new ParameterInfo[methods[i].Length][];

                for(int j = 0; j < methods[i].Length; j++)
                {
                    methodParameters[i][j] = methods[i][j].GetParameters();
                    Console.WriteLine("\t" + methods[i][j].Name + "(" + GetParameters(methodParameters[i][j]) + ")");
                }
			}

            Console.ReadLine();
        }

        static string GetParameters(ParameterInfo[] parInfo)
        {
            string result = "";

            foreach (var parameter in parInfo)
                result +=  parameter + ", ";

            return result;
        }

Так ведь — «на скорую руку»

Может код и ужасен, но ТС сказал

Не представляю как выглядят вытянутые из длл данные, как они отображаются?
Так что пыталась показать, что в сборке хранятся типы, у типов есть методы (атрибуты, конструкторы, поля и еще много чего интересного), а у методов есть параметры (+ атрибуты и т.д.)

Не понятно какие именно данные вы из сборки вы хотите вытянуть.
Покажите код DLL и скажите что хотите получить на выходе

на выходе хочу получить методы с атрибутом «тест».
prntscr.com/63qggs

Підписатись на коментарі