Search code examples
c#.netpostsharp

Field definitions changes by PostSharp not friendly to using lambda expressions


I'm using PostSharp's LocationInterceptionAspect to intercept invocations of fields and properties of a class. It is obvious that PostSharp changes such class at compile-time. However, it's getting in my way, and the problem isn't only related to elegance of code that depends on this functionality.

Namely, I also use lambda-expression to obtain the name of those fields and properties. Here's a simplified example, to demonstrate this:

    namespace Example
{
    using System.Linq.Expressions;
    public class Data
    {
        public string Field;

        public string Property { get; set; }
    }

    public class Process
    {
        public void Do()
        {
            string name1 = this.GetAttributeName<Data>(data => data.Field);
            // name1 = "<Field>k_OriginalField"

            string name2 = this.GetAttributeName<Data>(data => data.Property);
            // name2 = "Property"
        }

        private string GetAttributeName<DECLARING_TYPE>(Expression<Func<DECLARING_TYPE, object>> expression)
        {
            return (expression.Body as MemberExpression)?.Member?.Name;
        }
    }
}

It should be obvious: I would like the "<Field>k_OriginalField" to be "Field". Can anything be done here?

Sure, I could make some assumptions about the format of this string and parse out the value that I want, but that seems a little ugly solution to me. I do need to keep field definitions and obtaining their names as demonstrated, though (their purpose is much more complex than what's visible here). I'm not sure what's even going on internally with .NET's construction of that lambda-expression, since Data.Field clearly exists (I verified via disassembling also), but it's been changed into a property, and I guess I'm being handed a backing-field instead, and I'm confused as to why.

Thank you for your time.

EDIT: I figured out why this happens (I forgot to check earlier): PostSharp also changes usage of this "field" member (but I'm still questioning why), to this:

string name1 = this.GetAttributeName<Data>(data => data.<Field>k_OriginalField);
// name1 = "<Field>k_OriginalField"

I find this usage-replacement weird because the whole point of PostSharp's intercept-aspects is to redirect the execution flow (while allowing custom execution control), so adjusting invocations to those changes makes no sense to me. Both Data and Process classes are in the same assembly; perhaps separating them would solve the problem, but I cannot easily do that, and - again - it looks ugly as a solution. I'm hoping PostSharp team will have something to say about this.


Solution

  • I am not a PostSharp expert, but I don't think this is a decidable problem in the (most) general case.

    Think about it. PostSharp rewrites part of the type system of your application at build time, informed by whatever static analysis that it can execute at that moment, for all the relevant assemblies, versions, and namespaces reachable by then.

    It cannot see in the future and decide which candidate rewritings ought to be omitted because of client call sites that need to make different assumptions at builds that would occur at a later point in time, and which would look at the your same type system without looking thru PostSharp's lenses, or using different ones.

    That is how, I think, it must assume that all the rewritings, that it is instructed to do when it is invoked over your types, must be honored in a type-safe way everywhere they are applicable.

    Just my intuition.

    'HTH,