Сначала мы должны определить наши термины:
- Авто-свойство - свойство с резервным полем, автоматически генерируемым компилятором.
- Свойство с выражением тела - свойство, реализованное с использованием * Синтаксис 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 - это авто -свойство