简体   繁体   English

拦截调用C#中的属性get方法

[英]Intercept call to property get method in C#

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? 现在,是否有可能在C#中拦截对属性get方法的调用,运行其他一些方法并返回该方法的结果而不是属性值? 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). 缺点是这个类无法更改(在C#级别)。 Maybe some IL ? 也许有些IL?

Look into PostSharp: http://www.sharpcrafters.com/ 看看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. PostSharp实现面向方面的.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. 请注意,此问题的任何解决方案都将涉及一些运行时开销(一些内存,一些额外的时间来进行函数调用。)没有什么是完全免费的。

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. 如果你的类无法更改 ,你可以使用像PostSharp这样的工具 - 它允许你编织代码来拦截或替换对方法和属性的调用。

If you can change the code , then just avoid using an automatic property, and implement the get and set operations explicitly. 如果您可以更改代码 ,那么只需避免使用自动属性,并显式实现get和set操作。 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: 或者,您可以将属性定义为虚拟,并派生另一个类来更改getter和/或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 . 如果您只需要进行单元测试 ,您可能需要查看MoqTypeMock模拟工具。

Extend the class and do 扩展课程并做

public class MyPerson : Person
{
    public new int Id 
    { 
        get
        {
            foo();
            return base.Id;
        }
}

The .NET SDK has what you need already. .NET SDK已经满足您的需求。 You can round-trip most anything on the CLR by disassembly/reassembly (ildasm.exe and ilasm.exe) if you are careful. 如果你小心的话,你可以通过反汇编/重组(ildasm.exe和ilasm.exe)往返CLR上的大多数东西。 Make sure to start a "Visual Studio Command Prompt" so these tools are in your PATH. 确保启动“Visual Studio命令提示符”,以便这些工具位于PATH中。

1) ildasm person.exe 1)ildasm person.exe

2) File -> Dump (person.il) 2)文件 - >转储(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. 3)编辑和修改get_Name()方法:重要:在IL级别修改方法时,始终重新计算.maxstack ,因为Visual Studio .NET编译器将为大多数方法准确设置它,如果添加任何代码,则引发.maxstack用于处理该方法的运行时堆栈上的最大值数,如果不是,则会得到无效的程序。

  .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 4)重新组装:ilasm person.il

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;
        }
    }
}
public Class Person
{
    private int _id;
    public int ID
    {
      get{ MyMethod(); return _id; }
      set{ _id = value; }
    }
   // etc. etc. .....

 }
private bool _pp;
public bool Propery
{
  get { // your code}
  set { _pp = value; }
}

我认为您正在寻找面向方面的框架

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. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM