Reputation: 1528
Please imagine having following two properties inside a class:
public string Category { get; set; }
public string DisplayCategory => "SomeCategory"
Now I just want to collect all PropertyInfo
objects where the property itself is not computed
var properties = type.GetProperties();
var serializables = properties.Where(p => p.CanRead, true));
How do I find out via Reflection
if a property is a computed one so I can ignore it?
The reason I want to do this, is because I use Expression Trees
to automatically create queries that are processed via Entity Framework 6
. Entity Framework only creates columns for non-computed properties and therefore one can't query the computed ones.
See This Article
Upvotes: 4
Views: 993
Reputation: 2113
The below worked for me.
I was trying to see if I could find a difference between a computed property, and a property with no Set method:
public int Computed => 2;
public int NoSet { get; }
PropertyInfo.SetMethod
returns null for both.
Looking at the generated IL of the get
method, There is a CompilerGeneratedAttribute
on the NoSet
property, but not on the Computed
property:
.method public hidebysig specialname instance int32
get_Computed() cil managed
{
.maxstack 8
// [215 32 - 215 33]
IL_0000: ldc.i4.2
IL_0001: ret
}
.method public hidebysig specialname instance int32
get_NoSet() cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
= (01 00 00 00 )
.maxstack 8
// [217 28 - 217 32]
IL_0000: ldarg.0 // this
IL_0001: ldfld int32 TestNamespace.TestClass::'<NoSet>k__BackingField'
IL_0006: ret
}
So the check becomes:
if (property.SetMethod == null && property.GetMethod.GetCustomAttribute(typeof(CompilerGeneratedAttribute)) == null)
return "Computed Property";
Upvotes: 2
Reputation: 549
I use DelegateDecompiler and currently I have to manually add each computed property name to a custom configuration.
It would be nice if the ShouldDecompile method below could automatically determine which properties should be decompiled:
public class CustomDelegateDecompilerConfiguration : Configuration {
public static CustomDelegateDecompilerConfiguration Instance { get; } = new CustomDelegateDecompilerConfiguration();
public static void Enable() => Configuration.Configure(Instance);
public CustomDelegateDecompilerConfiguration() {
RegisterDecompileableMember<Person, string>(x => x.Name);
RegisterDecompileableMembers(typeof(string), nameof(string.IsNullOrWhiteSpace));
RegisterDecompileableMembers(typeof(CustomComputedMethods), new[] {
nameof(CustomComputedMethods.PersonName),
nameof(CustomComputedMethods.MonthInteger),
nameof(CustomComputedMethods.WholeMonthsBetween),
nameof(CustomComputedMethods.WholeYearsBetween)
});
}
public HashSet<MemberInfo> DecompileableMembers { get; } = new HashSet<MemberInfo>();
public override bool ShouldDecompile(MemberInfo memberInfo) => memberInfo.GetCustomAttributes(typeof(DecompileAttribute), true).Length > 0
|| memberInfo.GetCustomAttributes(typeof(ComputedAttribute), true).Length > 0
|| memberInfo.GetCustomAttributes(typeof(CompilerGeneratedAttribute), true).Length > 0
|| DecompileableMembers.Contains(memberInfo)
//*** Would be nice if auto detection was possible with non-existing methods below ***
//|| memberInfo.AutoProperty (One with a backing field automatically generated by the compiler)
//|| memberInfo.HasExpressionBody (One implemented using the => (lambda) syntax)
//|| memberInfo.HasFunctionBody (One implemented using the normal {...} syntax)
;
public override void RegisterDecompileableMember(MemberInfo prop) => DecompileableMembers.Add(prop);
public void RegisterDecompileableMember<T, TResult>(Expression<Func<T, TResult>> expression) where T : class => RegisterDecompileableMember(expression.Body.GetMemberInfo());
public void RegisterDecompileableMembers(Type type, params string[] memberNames) {
foreach(var tmi in type.GetMembers().Where(mi => memberNames.Contains(mi.Name))) {
DecompileableMembers.Add(tmi);
}
}
public void RegisterDecompileableMembers<T>(params string[] memberNames) where T : class => RegisterDecompileableMembers(typeof(T), memberNames);
}
An example class:
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
public string AlternativeFirstName { get; set; }
public string Name => string.Concat(AlternativeFirstName == string.Empty ? FirstName : AlternativeFirstName, " ", LastName);
}
Some example extension Methods:
public static class CustomComputedMethods {
public static string PersonName(string firstName, string lastName, string knownAs) => (knownAs ?? firstName).Trim() + " " + lastName.Trim();
public static long MonthInteger(this DateTime d) => checked(d.Year * 12 + d.Month);
public static int WholeMonthsBetween(this DateTime d, DateTime maxDate) => (int)(maxDate.MonthInteger() - d.MonthInteger() - (d.Day > maxDate.Day ? 1 : 0));
public static int WholeYearsBetween(this DateTime d, DateTime maxDate) => d.WholeMonthsBetween(maxDate) / 12;
}
Upvotes: 1