Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you make a method part of the default setter action in a property variable?

If you have multiple properties that implement the same method in the setter, is there a way to make it part of the default setter?

If I have multiple properties that call a Filter() when they are set, is there a way to push it into a "base setter" so that I don't have to have the Filter() call in every setter?

private string _MyVal1;
public string MyVal1 {
    get {
        return _MyVal1;
    }
    set {
        _MyVal1 = value;
        Filter();
        OnPropertyChanged("MyVal1");
    }
}

private string _MyVal2;
public string MyVal2 {
    get {
        return _MyVal2;
    }
    set {
        _MyVal2 = value;
        Filter();
        OnPropertyChanged("MyVal2");
    }
}

private string _MyValN;
public string MyValN {
    get {
        return _MyValN;
    }
    set {
        _MyValN = value;
        Filter();
        OnPropertyChanged("MyValN");
    }
}

So it turns into this:

private string _MyValN;
public string MyValN {
    get {
        return _MyValN;
    }
    set : FilterSetter {
        _MyValN = value;
        OnPropertyChanged("MyValN");
    }
}
like image 400
Bob. Avatar asked Mar 05 '13 15:03

Bob.


People also ask

Why use get set instead of public?

The main difference between making a field public vs. exposing it through getters/setters is holding control over the property. If you make a field public, it means you provide direct access to the caller. Then, the caller can do anything with your field, either knowingly or unknowingly.

What is get and set method in C#?

The get method returns the value of the variable name . The set method assigns a value to the name variable. The value keyword represents the value we assign to the property.

Why we use get set property in C#?

A get property accessor is used to return the property value, and a set property accessor is used to assign a new value. In C# 9 and later, an init property accessor is used to assign a new value only during object construction. These accessors can have different access levels.


2 Answers

A different way of doing this is to use interception like that provided by the Unity framework. With interception your class implements an interface and you would tell the framework that everytime a method is called on classes implementing that interface, run these interceptors. Your interceptors code can look to see if the method being called is prefixed with set_. Interceptor code executes once on the way to the function and once on the way back. On the way back, you can then have the interceptor call the filter method (assuming it is defined on the interface of course).

Concrete example:

Get Prerequisite Library

Use NuGet to add Unity and Unity extensions to your project

Define your interface to be intercepted: SomeObject.cs

using System;

namespace InterceptSetter
{
    interface ISomeObject
    {
        string SomeProperty { get; set; }
        void Filter();
    }

    public class SomeObject : ISomeObject
    {
        public string SomeProperty { get; set; }

        public void Filter()
        {
            Console.Out.WriteLine("Filter Called");
        }
    }
}

Define your Interception Behavior: SetterCallsFilterMethodBehavior.cs

using Microsoft.Practices.Unity.InterceptionExtension;
using System;
using System.Collections.Generic;
using System.Linq;

namespace InterceptSetter
{
    /// <summary>
    /// See http://msdn.microsoft.com/en-us/library/ff660871(v=pandp.20).aspx
    /// See http://msdn.microsoft.com/en-us/library/ff647107.aspx
    /// </summary>
    class SetterCallsFilterMethodBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            // we dont need anything
            return new[] { typeof(ISomeObject) };
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        { // Do not intercept non-setter methods
            if (!input.MethodBase.Name.StartsWith("set_"))
                return getNext()(input, getNext);

            IMethodReturn msg = getNext()(input, getNext);

            // post processing. this is where we call filter
            if (input.Target is ISomeObject)
            {
                (input.Target as ISomeObject).Filter();
            }

            return msg;
        }

        /// <summary>
        /// We always execute
        /// </summary>
        public bool WillExecute
        {
            get { return true; }
        }
    }
}

Write a test console program: Program.cs

using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using System;

namespace InterceptSetter
{
    class Program
    {
        static void Main(string[] args)
        {
            UnityContainer container = new UnityContainer();

            container.AddNewExtension<Interception>();
            container.RegisterType<ISomeObject, SomeObject>(
                      new Interceptor<TransparentProxyInterceptor>(),
                      new InterceptionBehavior<SetterCallsFilterMethodBehavior>());

            // we must get our instance from unity for interception to occur
            ISomeObject myObject = container.Resolve<ISomeObject>();
            myObject.SomeProperty = "Hello Setter";

            Console.ReadLine();
        }
    }
}

Running this you will see that the interceptor does in fact call the filter method (which prints to the console).

Unity is not the only dependency injection / interception framework out there (google PostSharp). Unity is the one i am familiar with so thats what this example uses.

Sources / See Also:

  1. http://msdn.microsoft.com/en-us/library/ff660871(v=pandp.20).aspx - Good diagram depicting the flow of interception
  2. http://msdn.microsoft.com/en-us/library/ff647107.aspx - overkill of detail showing different interception techniques
like image 148
Steven Magana-Zook Avatar answered Nov 01 '22 04:11

Steven Magana-Zook


You can create generic setter method and call that from each property setter:

private void Set<T>(ref T field, T value, string propertyName)
{
    field = value;
    Filter();
    OnPropertyChanged(propertyName);
}

Then your properties look like:

public string SomeProperty
{
    get { return this.someField; }
    set
    {
        Set(ref this.someField, value, "SomeProperty");
    }
}
like image 3
Lee Avatar answered Nov 01 '22 05:11

Lee