Перехватить вызов метода get свойства в C # - PullRequest
2 голосов
/ 22 апреля 2010

Давайте предположим, что у нас есть этот класс:

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

Теперь, возможно ли в C # перехватить вызов метода get свойства, запустить какой-либо другой метод и вернуть результат этого метода вместо значения свойства? Я хотел бы иметь возможность сделать некоторую дополнительную логику за сценой. Недостатком является то, что этот класс нельзя изменить (на уровне C #). Может быть, какой-нибудь IL?

Ответы [ 9 ]

7 голосов
/ 22 апреля 2010

Просмотр PostSharp: http://www.sharpcrafters.com/

Это реализует именно то, что вы ищете, и многое другое.

PostSharp реализует Аспектно-ориентированное программирование для .NET. Это коммерческий продукт. Очень круто.

Просто имейте в виду, что любое решение этой проблемы потребует некоторых накладных расходов времени выполнения (некоторой памяти, дополнительного времени для выполнения вызовов функций.)

6 голосов
/ 22 апреля 2010

Если ваш класс не может быть изменен , вы можете использовать такие инструменты, как PostSharp - он позволяет вам вносить код, который перехватывает или заменяет вызовы методов и свойств.

Если вы можете изменить код , просто избегайте использования автоматического свойства и явно выполняйте операции get и set. Тогда вы можете делать все, что вам нужно. Кроме того, вы можете определить свойство как виртуальное и получить другой класс, чтобы изменить поведение метода получения и / или установки:

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 { ... } }
}

Если вам это нужно только для модульного тестирования , вы можете обратиться к инструментам насмешек, таким как Moq или TypeMock .

1 голос
/ 22 апреля 2010

.NET SDK уже содержит то, что вам нужно.Если вы осторожны, вы можете использовать все, что угодно в CLR, путем разборки / повторной сборки (ildasm.exe и ilasm.exe).Обязательно запустите «Командную строку Visual Studio», чтобы эти инструменты были в вашей переменной PATH.

1) ildasm person.exe

2) Файл -> Дамп (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

1 голос
/ 22 апреля 2010

Расширьте класс и сделайте

public class MyPerson : Person
{
    public new int Id 
    { 
        get
        {
            foo();
            return base.Id;
        }
}
0 голосов
/ 22 апреля 2010

Если вы не можете изменить сам класс, вы можете использовать метод расширения для получения имени. Это изменит способ доступа к данным, поэтому он также может быть недоступен. Вот как вы это сделаете, если вам интересно:

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

Надеюсь, это поможет.

0 голосов
/ 22 апреля 2010

Я думаю, вы ищете Aspect Oriented Framework .

0 голосов
/ 22 апреля 2010
private bool _pp;
public bool Propery
{
  get { // your code}
  set { _pp = value; }
}
0 голосов
/ 22 апреля 2010
public Class Person
{
    private int _id;
    public int ID
    {
      get{ MyMethod(); return _id; }
      set{ _id = value; }
    }
   // etc. etc. .....

 }
0 голосов
/ 22 апреля 2010

Не с авто-свойствами, нет.

Но вы могли бы сделать:

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