17

I am writing a decorating proxy using Castle DynamicProxy. I need the proxy's interceptor to intercept only property writes (not reads) so I am checking the name of the method thusly:

public void Intercept(IInvocation invocation)
{
    if (invocation.Method.Name.StartsWith("set_")
    {
        // ...
    }

    invocation.Proceed();
}

Now this works fine but I don't like the fact my proxy has intimate knowledge of how properties are implemented: I'd like to replace the method name check with something akin to:

if (invocation.Method.IsPropertySetAccessor)

Unfortunately my Google-fu has failed me. Any ideas?

Paul Ruane
  • 37,459
  • 12
  • 63
  • 82

6 Answers6

19

You could check whether a property exists for which this method is the setter (untested):

bool isSetAccessor = invocation.Method.DeclaringType.GetProperties() 
        .Any(prop => prop.GetSetMethod() == invocation.Method)

(Inspiration taken from Marc's answer to a related question.)

Community
  • 1
  • 1
Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • 3
    Looks very inneficient – thepirat000 Sep 27 '16 at 16:30
  • @thepirat000: Well, if `GetSetMethod` is O(1), this would be O(n). That's probably not optimal (and I'll definitely upvote any alternative answer which is equally readable and yields better performance), but I'm sure you know the saying about premature optimization being the root of all evil... – Heinzi Sep 27 '16 at 18:06
  • I would suggest you to check if the method has "get_" prefix (casesensitive) and remove it from the method collection (still O(n) complexity - which is rather cheap). In addition you can add `Dictionary` instance to hold already checked types which first gives you the complexity of O(n) but afterwards O(1) – Roi Shabtai May 23 '17 at 08:50
7

There isn't any voodoo of which I'm aware. You could, perhaps, strip the set_, look for a property with that name, and compare the MethodInfo instance (invocation.Method) to the property accessor (GetSetMethod()) - however, I can't honestly say (without checking) whether you will get the same MethodInfo instance (even if it is the same method).

if(method.IsSpecialName && method.Name.StartsWith("set_"))
{
    var prop = typeof (Foo).GetProperty(method.Name.Substring(4),
           BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    var accessor = prop.GetSetMethod();
    bool isSame = accessor == method;
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
3

I'm not sure what kind of type the invocation.Method is, but if you can get the PropertyInfo you can use the IsSpecialName. Unfortunately this tells not only if the property is a set_ or _get but also if it is an overloaded operator.

dowhilefor
  • 10,971
  • 3
  • 28
  • 45
-1

First, you can examine the MemberType property of MethodInfo class to see if it's a Property.

Now, you should try to guess if it's a get or a set. If you don't want to analyse the name (someone might name a method "set_Something"), then you can check the arguments.

  • If the property accessor accepts one parameter and returns void, it is a set
  • If the property accessor returns one value and doesn't pick parameters, it is a get

You may be interested only in the first check

usr-local-ΕΨΗΕΛΩΝ
  • 26,101
  • 30
  • 154
  • 305
  • 2
    Just asking out of curiosity. What about the this[] operator? I think it allows one parameter. – dowhilefor Oct 19 '11 at 10:03
  • The `MemberType` of a property accessor method is `MemberTypes.Method` not `MemberTypes.Property`. Thanks anyway. – Paul Ruane Oct 19 '11 at 10:10
  • @dowhilefor: good point!!! Can you see in Reflector/ILDASM what is the result and tell us? I don't have both Reflector and an assembly with a this accessor at hand, but mscorlib.dll should be full of them – usr-local-ΕΨΗΕΛΩΝ Oct 19 '11 at 10:13
-1

from your MethodInfo object get the MemberType property which should say this is a Property type so you should be able to cast it to PropertyInfo instead. that object exposes the property CanWrite which tells if this is a setter.

mtijn
  • 3,610
  • 2
  • 33
  • 55
  • Hmm, the documentation seems to imply that the `MemberType` will be `MemberTypes.Method` for `MethodInfo` objects. – Paul Ruane Oct 19 '11 at 10:06
  • hmm, you're right, I have overlooked this and expected it to be MemberTypes.Property for MethodInfo objects created for properties, maybe it is I'm not sure anymore now – mtijn Oct 19 '11 at 10:09
  • 1
    I've just run a test: the `MemberType` of a property accessor method is `MemberTypes.Method` not `MemberTypes.Property` so this does not fly. Thanks anyhow. – Paul Ruane Oct 19 '11 at 10:09
-4

I think you may try using extension methods: http://msdn.microsoft.com/en-us/library/bb383977.aspx

mao
  • 1,364
  • 3
  • 14
  • 26
  • Thanks, but this is how my current solution works. I am looking for one that does not require my application to know about C# compiler implementation details. – Paul Ruane Oct 19 '11 at 10:00
  • He could use an extension method to add an `IsPropertySetAccessor` method to the `MethodInfo` type, but the problem he has is what would go in that method that's better than what he has now. **"I don't like the fact my proxy has intimate knowledge of how properties are implemented"** – George Duckett Oct 19 '11 at 10:01
  • 2
    This answer is pretty unhelpful - the question seems to be pointing more at the "what would go *inside* a method to determine this" – Marc Gravell Oct 19 '11 at 10:08