views:

465

answers:

9

Let's assume that we have this class:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Now, is it possible in C# to intercept call to property get method, run some other method and return result of that method instead of property value? I'd like to be able to do some additional logic behind the scene. The downside is that this class can't be changed (on C# level). Maybe some IL ?

+1  A: 

Extend the class and do

public class MyPerson : Person
{
    public new int Id 
    { 
        get
        {
            foo();
            return base.Id;
        }
}
thelost
This will not compile. If you correct the case and return `this.Id`, you'll get a `StackOverflowException` (since you're calling the same property over and over again). It needs to call `base.Id`, but that will only work if the code references the object as `MyPerson` and never as `Person`.
Adam Robinson
Thanks for the tips!
thelost
Bonus points for an actual StackOverflowException comment
ccomet
+4  A: 

If your class can't be changed, you can look into using tools like PostSharp - it allows you to weave in code that intercepts or replaces calls to methods and properties.

If you can change the code, then just avoid using an automatic property, and implement the get and set operations explicitly. Then you can do whatever you need. Alternatively, you can define the property as virtual and derive another class to change th behavior of the getter and/or setter:

public class Person 
{ 
  public virtual int Id { get; set; } 
  public virtual string Name { get; set; } 
} 

public class PersonDerived : Person
{
  public override int Id { get { ... } set { ... } }
  public override string Name { get { ... } set { ... } }
}

If you need this just for unit testing, you may want to look into mocking tools like Moq or TypeMock.

LBushkin
+6  A: 

Look into PostSharp: http://www.sharpcrafters.com/

This implements exactly what you're looking for, and a whole lot more.

PostSharp implements Aspect Oriented Programming for .NET. Its a commercial product. Very cool.

Just be aware that any solution to this problem will involve some runtime overhead (some memory, some extra time to make function calls.) Nothing is absolutely free.

kmontgom
No, he said "can't be changed (_on the C# level_). Maybe some IL?"
mrjoltcola
PostSharp does NOT change the source code of the classes. It alters the IL produced from compilling the classes; I believe that the original poster was open to having the IL changed.
kmontgom
@kmontgom: my comment was to the original commenter on your answer, not to your answer (which I agree with). The comment I responded to has been deleted, and left it appearing I was responding to you. Sorry I did not address the person to clarify.
mrjoltcola
A: 

Not with auto-properties, no.

But you could do:

public class Person
{
    private int _id;

    public int Id
    {
        get
        {
            // Do some logic or call a method here
            return _id;
        }
        set
        {
            if(value <= 0)
                throw new CustomInvalidValueException();

            _id = value;
        }
    }
}
Justin Niessner
A: 
public Class Person
{
    private int _id;
    public int ID
    {
      get{ MyMethod(); return _id; }
      set{ _id = value; }
    }
   // etc. etc. .....

 }
Matthew Vines
A: 
private bool _pp;
public bool Propery
{
  get { // your code}
  set { _pp = value; }
}
TriLLi
A: 

I think you're looking for an Aspect Oriented Framework.

danbystrom
A: 

If you can't change the class itself, you might consider using an extension method to get the name. This will change the way you access the data, so it might not be an option either. This is how you'd do it, if you're interested:

public static class PersonExtensions
{
    public static string GetName(this Person p)
    {
        foo();
        return p.Name;
    }
}

You would then access the name this way:

Person myPerson = new Person();
string name = myPerson.GetName();  // Also calls foo() for you extra processing

Hope this helps.

Adam Barney
Thanks, but I need to deliver this class unchanged, that end user can use it like every other "normal" class. I know it's hard :)
michajas
+1  A: 

The .NET SDK has what you need already. You can round-trip most anything on the CLR by disassembly/reassembly (ildasm.exe and ilasm.exe) if you are careful. Make sure to start a "Visual Studio Command Prompt" so these tools are in your PATH.

1) ildasm person.exe

2) File -> Dump (person.il)

3) Edit and modify the get_Name() method: IMPORTANT: When modifying a method at the IL level, always recalculate .maxstack, since the Visual Studio .NET compilers will have set it exactly for most methods, if you add any code, raise .maxstack to handle the maximum # of values on the runtime stack for that method, if not you'll get an invalid program.

  .method public hidebysig specialname instance string get_Name() cil managed
  {
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
    // Code size       11 (0xb)
    .maxstack  2
    .locals init (string V_0)
    IL_0000:  ldarg.0
    IL_0001:  ldfld      string Person::'<Name>k__BackingField'
    IL_0006:  stloc.0
    IL_0009:  ldloc.0
        IL_000a:  ldstr "IL code inserted here"
        call    void [mscorlib]System.Console::WriteLine(string)
    IL_001a:  ret
 } // end of method Person::get_Name

4) Re-assemble : ilasm person.il

mrjoltcola
Ok, thanks. But let us assume that I need to generate this class based on some metadata (something like ORM generating classes based on table description, but it's not ORM :P). Now end user can use this class in his code and I want to be able to inject method call in this scenario dynamically (of course he uses some kind of framework of mine). I hope you get what I mean :)
michajas
Well sure, but that is another question (given your stated question above). You said C# cannot be changed, so the assumption is you are the end user of the class. If you generate it from an ORM, you are the creator of the original class.
mrjoltcola