Вызывать метод всякий раз, когда вызывается свойство - PullRequest
0 голосов
/ 07 мая 2018

Есть ли способ добавить атрибут или что-то в класс, чтобы при вызове свойства этого класса вызывался метод?

В основном у меня есть классы, которые содержат datarow, и вместо доступа к отдельному столбцу, например: (DataRow ["some_column_name"]), я хочу получить к ним доступ, используя свойства вместо этого: (MyClass.some_column_name).

Моя текущая работа заключается в использовании отражения для динамической передачи имени столбца в качестве параметров, например:

public string some_column_name
    {
        get
        {

            return (string)GetValue(MethodBase.GetCurrentMethod().Name);
        }
        set
        {
            SetValue(MethodBase.GetCurrentMethod().Name, value);
        }
    }

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

В приведенном ниже примере кода содержится метод get и set value из приведенного выше фрагмента кода. Эти методы будут в базовом классе:

private DataRow some_table;

protected object GetValue(string columnName)
{
    return some_table[columnName.Substring(columnName.IndexOf('_') + 1)];
}

protected object SetValue(string columnName, object value)
{
    return  some_table[columnName.Substring(columnName.IndexOf('_') + 1)] = value;
}

Ответы [ 2 ]

0 голосов
/ 07 мая 2018

Ниже приведена простая рабочая версия вашего кода с использованием PostSharp AOP. Результат здесь будет TestProperty , так как мы обрезаем get_ и set_. В OnInvoke возможно гораздо больше обработки, MethodInterceptionArgs может использоваться для внесения множества изменений в вызывающую функцию, затем мы можем выбрать возврат из самого вызова PostSharp или дальнейшее выполнение метода. Вы также можете запланировать использование функций AOP, таких как OnMethodBoundaryAspect, которые могут выполняться в случае успеха или неудачи метода

namespace TestAOP
{
    class Program
    {
        static void Main(string[] args)
        {
           var t = new Test();

           var x = t.TestProperty;

           Console.WriteLine(x);

           Console.Read();
        }
    }

    public class Test
    {
        private string _test = "InitialValue";

        [CustomProperty]
        public string TestProperty
        {
            get => _test;
            set => _test = value;
        }
    }

    [Serializable]
    public sealed class CustomPropertyAttribute : MethodInterceptionAspect
    {
        public override void OnInvoke(MethodInterceptionArgs args)
        {
           args.ReturnValue = args.Method.Name.Substring(args.Method.Name.IndexOf("_", StringComparison.Ordinal) + 1);

        }
    }
}
0 голосов
/ 07 мая 2018

Вы можете использовать атрибут [CallerMemberName]. Если вы украсите параметр метода этим атрибутом так:

protected object GetValue([CallerMemberName] string columnName = null)
{
    return some_table[columnName.Substring(columnName.IndexOf('_') + 1)];
}

protected object SetValue(object value, [CallerMemberName] string columnName = null)
{
    return  some_table[columnName.Substring(columnName.IndexOf('_') + 1)] = value;
}

Компилятор будет использовать имя члена метода (метода) вместо значения по умолчанию. Таким образом, ваша собственность становится просто:

public string some_column_name
{
    get
    {
        // current method name ("some_column_name") will be passed 
        // as "column" parameter
        return (string)GetValue();
    }
    set
    {
        // same here
        SetValue(value);
    }
}

Другой альтернативой может быть наследование от DynamicObject:

public class DynamicRow : DynamicObject {
    public override bool TryGetMember(GetMemberBinder binder, out object result) {
        // this will be called when you access dynamic property
        // like x.some_column_name
        result = GetValue(binder.Name);
        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value) {
        // this will be called when you assign dynamic property
        // like x.some_column_name = "some value"
        SetValue(binder.Name, value);
        return true;
    }

    private DataRow some_table;

    protected object GetValue(string columnName) {
        return some_table[columnName.Substring(columnName.IndexOf('_') + 1)];
    }

    protected object SetValue(string columnName, object value) {
        return some_table[columnName.Substring(columnName.IndexOf('_') + 1)] = value;
    }
}

Тогда вы можете использовать это так:

dynamic x = new DynamicRow();
object val = x.some_column_name;
x.some_column_name = "some value";

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...