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

时间:2010-04-22 14:05:57

标签: c# .net cil dynamic

我们假设我们有这个类:

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

现在,是否可以在C#中拦截对属性get方法的调用,运行其他一些方法并返回该方法的结果而不是属性值?我希望能够在幕后做一些额外的逻辑。 缺点是这个类无法更改(在C#级别)。也许有些IL?

9 个答案:

答案 0 :(得分:7)

查看PostSharp:http://www.sharpcrafters.com/

这实现了你正在寻找的东西,以及更多。

PostSharp为.NET实现面向方面编程。它是一种商业产品。很酷。

请注意,此问题的任何解决方案都会涉及一些运行时开销(一些内存,一些额外的时间来进行函数调用。)没有什么是完全免费的。

答案 1 :(得分:6)

如果您的课程无法更改,您可以查看使用PostSharp等工具 - 它允许您编写代码来拦截或替换对方法和属性的调用。< / p>

如果您可以更改代码,则只需避免使用自动属性,并明确实施get和set操作。然后你可以做任何你需要的事情。或者,您可以将属性定义为虚拟,并派生另一个类来更改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 { ... } }
}

如果您只需要进行单元测试,您可能需要查看MoqTypeMock等模拟工具。

答案 2 :(得分:1)

扩展课程并执行

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

答案 3 :(得分:1)

.NET SDK已经满足您的需求。如果你小心的话,你可以通过反汇编/重组(ildasm.exe和ilasm.exe)往返CLR上的大多数东西。确保启动“Visual Studio命令提示符”,以便这些工具位于PATH中。

1)ildasm person.exe

2)文件 - &gt;转储(person.il)

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

答案 4 :(得分:0)

没有自动属性,没有。

但你可以这样做:

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;
        }
    }
}

答案 5 :(得分:0)

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

 }

答案 6 :(得分:0)

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

答案 7 :(得分:0)

我认为你正在寻找Aspect Oriented Framework

答案 8 :(得分:0)

如果您无法更改类本身,可以考虑使用扩展方法来获取名称。这将改变您访问数据的方式,因此它也可能不是一个选项。如果您有兴趣,这就是您的工作方式:

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

然后您将以这种方式访问​​该名称:

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

希望这有帮助。