Различить guish между свойством только для получения и свойством тела выражения? - PullRequest
3 голосов
/ 11 марта 2020

Можно ли с помощью отражения различить guish между свойством только для получения и свойством тела выражения?

class MyClass
{
    DateTime GetterOnly { get; }

    DateTime ExpressionBody => DateTime.Now;
}

Например, как можно выполнить описанный ниже метод?

enum PropertyKind
{
    NotInteresting,

    GetterOnly,

    ExpressionBody,
}

PropertyKind GetPropertyKind(PropertyInfo propertyInfo)
{
    if (propertyInfo.GetSetMethod(true) == null)
    {
        // what goes here??
    }

    return PropertyKind.NotInteresting;
}

Связанный пост: В чем разница между автоматическими свойствами get-only и свойствами тела выражения?

1 Ответ

1 голос
/ 11 марта 2020

Сначала мы должны определить наши термины:

  • Авто-свойство - свойство с резервным полем, автоматически генерируемым компилятором.
  • Свойство с выражением тела - свойство, реализованное с использованием * Синтаксис 1006 * (лямбда).
  • Свойство с функциональным телом - реализовано с использованием обычного синтаксиса {...}.

Важно отметить, что это , а не можно провести различие между свойством выражения-выражения и свойством функции-тела, потому что фактически для обоих будет сгенерирован один и тот же IL.

Однако я полагаю, что то, что вы действительно хотите, это уметь сказать разница между авто-свойством и не-авто-свойством.

Это возможно, потому что компилятор генерирует вспомогательное поле, украшенное [CompilerGeneratedAttribute] и именем, полученным из свойства, которое можно проверить на .

В настоящее время именем вспомогательного поля всегда является " k__BackingField" (где PropertyName - это имя свойства), и это верно для b др. Net 4.6 и. Net Core 3.1 - но, конечно, это ни в коем случае не гарантирует, что никогда не изменится, поэтому любой код, основанный на этом, может сломаться для будущих версий C# компилятора.

Несмотря на это довольно большое предостережение, вы можете написать метод, чтобы проверить, реализует ли PropertyInfo авто-свойство, например, так:

public static bool IsAutoProperty(PropertyInfo property)
{
    string backingFieldName = $"<{property.Name}>k__BackingField";
    var    backingField     = property.DeclaringType.GetField(backingFieldName, BindingFlags.NonPublic | BindingFlags.Instance);

    return backingField != null && backingField.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) != null;
}

Это проверяет свойство, чтобы увидеть, если (a) оно имеет вспомогательное поле с указанным c именем, полученным из имени свойства, и (b) это вспомогательное поле генерируется компилятором.

Я не думаю, что это хорошая идея, поскольку оно опирается на недокументированное и эмпирически определенное поведение компилятора, поэтому требуется осторожность!

Вот скомпилируемое консольное приложение для демонстрации:

using System;
using System.Reflection;
using System.Runtime.CompilerServices;

namespace ConsoleApplication1
{
    static class Program
    {
        static void Main(string[] args)
        {
            var type = typeof(MyClass);

            foreach (var property in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
            {
                if (IsAutoProperty(property))
                    Console.WriteLine($"{property.Name} is an auto-property");
            }
        }

        public static bool IsAutoProperty(PropertyInfo property)
        {
            string backingFieldName = $"<{property.Name}>k__BackingField";
            var    backingField     = property.DeclaringType.GetField(backingFieldName, BindingFlags.NonPublic | BindingFlags.Instance);

            return backingField != null && backingField.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) != null;
        }
    }

    class MyClass
    {
        DateTime GetterOnly { get; }

        DateTime ExpressionBody => DateTime.Now;
    }
}                                                                                                 

Это выводит:

GetterOnly - это авто -свойство

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...