Подтвердить что ты не робот

Отражение. Что мы можем добиться от этого?

Я читаю и изучаю отражение в С#. Было бы хорошо знать, как это может помочь мне в моей повседневной работе, поэтому я хочу, чтобы люди с большим опытом, чем я, рассказывали мне образцы или идеи о том, какие вещи мы можем достичь, используя это или как мы можем уменьшить количество кода что мы пишем.

Спасибо.

4b9b3361

Ответ 1

Недавно я использовал его для добавления настраиваемых атрибутов в поля в моем перечислении:

public enum ShapeName
{
    // Lines
    [ShapeDescription(ShapeType.Line, "Horizontal Scroll Distance", "The horizontal distance to scroll the browser in order to center the game.")]
    HorizontalScrollBar,
    [ShapeDescription(ShapeType.Line, "Vertical Scroll Distance", "The vertical distance to scroll the browser in order to center the game.")]
    VerticalScrollBar,
}

Использование отражения для получения поля:

    public static ShapeDescriptionAttribute GetShapeDescription(this ShapeName shapeName)
    {
        Type type = shapeName.GetType();
        FieldInfo fieldInfo = type.GetField(shapeName.ToString());
        ShapeDescriptionAttribute[] attribs = fieldInfo.GetCustomAttributes(typeof(ShapeDescriptionAttribute), false) as ShapeDescriptionAttribute[];

        return (attribs != null && attribs.Length > 0) ? attribs[0] : new ShapeDescriptionAttribute(ShapeType.NotSet, shapeName.ToString());
    }

Класс атрибута:

[AttributeUsage(AttributeTargets.Field)]
public class ShapeDescriptionAttribute: Attribute
{
    #region Constructor
    public ShapeDescriptionAttribute(ShapeType shapeType, string name) : this(shapeType, name, name) { }

    public ShapeDescriptionAttribute(ShapeType shapeType, string name, string description)
    {
        Description = description;
        Name = name;
        Type = shapeType;
    }
    #endregion

    #region Public Properties
    public string Description { get; protected set; }

    public string Name { get; protected set; }

    public ShapeType Type { get; protected set; }
    #endregion
}

Ответ 2

Вообще говоря, Reflection позволяет получить доступ к метаданным об объектах. Объединение отражений с другими методами позволяет сделать вашу программу более динамичной. Например, вы можете загрузить DLL и определить, содержит ли она реализацию интерфейса. Вы можете использовать это для обнаружения dll, поддерживающих функциональность во время выполнения. Использование может использоваться для расширения приложения без перекомпиляции и без перезапуска.

Intellisense в Visual Studio использует отражение, чтобы предоставить вам информацию об объектах, которые вы используете.

Обратите внимание, что использование Reflection происходит за счет стоимости. Отражение объекта может быть медленным. Но если вам это нужно, Reflection - очень полезный инструмент.

Ответ 3

Это неоценимо для библиотечного кода, который не нуждается в том, чтобы знать о вызывающем, как с дженериками, но более богатый доступ к данным. Примеры:

  • ORM (материализация и т.д.)
  • Сериализация/десериализация
  • клонирование объектов/глубокая копия
  • UI/код привязки (строго это ComponentModel, но вы можете смешать два - например, HyperDescriptor)

Вы должны, конечно, попытаться свести к минимуму количество отражения, которое вы делаете, но вы можете уменьшить стоимость, кэшируя делегатов от Delegate.CreateDelegate/Expression/DynamicMethod

Ответ 4

Одно из многих: вы можете создать подключаемую архитектуру, в которой вы указываете имя класса для использования в файле конфигурации. Используя отражение, вы можете взять эту строку и создать экземпляр запрошенного объекта. Если этот объект реализует известный интерфейс, вы можете использовать его через обычный (не отраженный) код.

Ответ 5

Я использовал отражение, чтобы позволить мне больше гибкости, отвечающей постоянно меняющимся требованиям. То есть клиент постоянно менял свое мнение о том, где разместить таблицу базы данных в базе данных. Все, что я сделал, это проверить объект на свои поля и вызвать конструкторы объектов этих полей внутри самого объекта. Тогда, если одна таблица должна быть найдена где-то в другом месте? Нажмите, вставьте, сделайте.

Это не вышло в финальной постановке, заметьте, но во время итеративной фазы удалили часть шаблона, который мне нужно было бы изменить.

Ответ 6

Я использовал отражение, чтобы облегчить перевод элементов управления, таких как метки и кнопки на наших формах. Используя отражение, я просмотрел все элементы управления в своей форме и напишу имя, текст и название элемента управления в файл XML. После того, как заголовок и текст управления переводится в XML, файл считывается при установке каждого заголовка элемента управления и текста, найденного в XML, на его переведенные значения.
Наши формы должны быть переведены на несколько разных языков, и использование рефлексии помогло нам сэкономить много времени.

Ответ 7

Окно свойств в VS основано на отражении - если вы создаете пользовательский элемент управления, вы можете изменить любые свойства на нем из PropertyGrid (его также можно использовать, если хотите) сразу. Конечно, вы можете добавлять атрибуты, чтобы улучшить способ отображения (к которым обращаются через отражение).

Я также использовал его для реализации пользовательского двоичного класса сериализации.

Здесь у меня есть класс, где я использую отражение для сериализации/де-сериализации его - и предоставляет атрибуты для дополнительной информации пользовательского интерфейса.

[TypeConverter(typeof(IndexedExpandableObjectConverter))]
[BinarySerializeable]
public sealed class Socket
{
    #region Fields (7) 

    [SerializedPosition(0)]
    Byte _mode = 1;

    ...

    [SerializedPositionAttribute(4)]
    UInt16 _localPort;

    ...

#region Свойства (5)

    [DisplayName("Listning Port")]
    [Description("The port which the socket will listen for connections on")]
    [DisplayIndex (0)]
    public UInt16 LocalPort
    {
        get { return _localPort; }
        set { _localPort = value; }
    }

    ...

И функция сериализации - как вы можете видеть, она просто берет объект и порядок байтов (endianness), который вы хотите. Все остальное определяется отражением. По умолчанию SerializationProvider работает с атрибутами SerializedPosition в полях внутри объекта (частный или нет).

public static Byte[] Serialize(Object obj, ByteOrder streamOrder)
{

    var provider = GetProvider(obj);

    if (provider.CanSerialize(obj.GetType()))
        return provider.Serialize(obj, streamOrder);

    throw new ArgumentException(obj.GetType() + " is non-serialisable by the specified provider '" + provider.GetType().FullName + "'.");
}


private static IBinarySerializatoinProvider GetProvider(Object obj)
{

    var providerAttrib = Reflector.GetAttribute<BinarySerializationProviderAttribute>(obj);

    if (providerAttrib != null)
        return CreateProvider(providerAttrib.ProviderType);

    return CreateProvider(typeof(SerializationProvider));
}

Ответ 8

Это способ выполнения методов на основе перечисления или магической строки...


    public enum ReflectionTestMethods
    {
        MethodA,
        MethodB,
        MethodC
    }
    public class ReflectionTest
    {

        public void Execute(ReflectionTestMethods method)
        {
            MethodInfo methodInfo = GetType().GetMethod(method.ToString()
                , BindingFlags.Instance | BindingFlags.NonPublic);
            if (methodInfo == null) throw new NotImplementedException(method.ToString());
            methodInfo.Invoke(this, null);
        }

        private void MethodA()
        {
            Debug.Print("MethodA");
        }

        private void MethodB()
        {
            Debug.Print("MethodB");
        }

        private void MethodC()
        {
            Debug.Print("MethodC");
        }
    }

Но это может быть лучшее решение...


    public class ActionTest
    {
        private readonly Dictionary _actions = new Dictionary();

        public ActionTest()
        {
            _actions.Add(ReflectionTestMethods.MethodA.ToString(), new Action(MethodA));
            _actions.Add(ReflectionTestMethods.MethodB.ToString(), new Action(MethodB));
            _actions.Add(ReflectionTestMethods.MethodC.ToString(), new Action(MethodC));
        }

        public void Execute(ReflectionTestMethods method)
        {
            if (!_actions.ContainsKey(method.ToString())) 
                throw new NotImplementedException(method.ToString());
            _actions[method.ToString()]();
        }

        private void MethodA()
        {
            Debug.Print("MethodA");
        }

        private void MethodB()
        {
            Debug.Print("MethodB");
        }
        private void MethodC()
        {
            Debug.Print("MethodC");
        }
    }

Ответ 9

Я использовал только отражение в производственном коде. Это была ситуация, когда мне приходилось вносить коррективы в то, что до этого момента было стандартизированным использованием определенного метода класса в рутине запуска (жаль, что это не было более точным - это было давно, а подробности туманно). Единственный способ обойти эту проблему состоял в том, чтобы ввести другую версию метода и изучить различные критерии/условия кода и т.д. Во время выполнения, чтобы определить, какой метод я должен вызывать. Это был довольно компактный кусок кода, который обеспечил сукцинтальное решение того, что в противном случае было бы грязной проблемой для решения.

Ответ 10

Вот некоторые вещи, которые я использовал. Отражение для этого было бы чрезвычайно сложно или невозможно без него:

  • Мой порт С# StringTemplate. Отражение используется для извлечения свойств динамических объектов.
  • Компилятор CLI JIT написан в управляемом коде.

Managed Extensibility Framework (новая библиотека .NET) использует отражение для:

  • Найдите и составьте детали, включая применение Импортирования.
  • Это позволяет избежать загрузки сборок для выполнения до тех пор, пока не потребуется их содержимое.

Ответ 11

Я предполагаю, что "автономное" приложение, где каждый объект, который вы используете, известен во время компиляции, вы не используете много размышлений.

Но когда вы пишете библиотечный или каркасный код, который должен использовать объекты, которые неизвестны (полностью - вы можете знать о интерфейсах или базовых словах) во время компиляции, отражение может быть бесценным для работы с этими объектами.

Ответ 12

Я использую его для:

  • Включение зависимостей
  • Обходные пути для Microsoft не имеют мотивации добавлять такие вещи, как "ковариантные/контравариантные общие" и "новые() ограничения с параметрами"
  • Аспектно-ориентированное программирование (в некоторой степени, в основном я использую PostSharp)

Ответ 13

Размышления хороши для решений "позднего связывания", где вы не хотите иметь физическую ссылку, связанную с вашим проектом, а скорее "подключайте" ее позже. Таким образом, если ссылка не существует, и она не является критичной, вы не получаете никаких ошибок, связанных с отсутствием ссылок. Вы получаете управляемую ошибку, с которой вы можете справиться.

Ответ 14

Классическое использование, которое у меня есть для использования Red Gate.NET Reflector, чтобы лучше понять механику самой структуры .Net. Вы когда-нибудь задавались вопросом, как и почему конкретный объект рамки работает так, как он есть, или вы когда-либо были немного в тупике, потому что почему-то не работает так, как вы думали?

Иногда документация может быть немного потрепанной, если не сказать больше, но используя рефлексию и инструмент Redgate, вы можете обнюхивать в коде фреймворков, чтобы лучше понять, как/почему/что из всего этого.

Более чем несколько ошибок были обнаружены в коде CLR через "MS outsiders" с использованием отражения.