Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically generate property getter/setter through reflection or similar

Imagine the following class:

public class Settings
{
    [FileBackedProperty("foo.txt")]
    public string Foo { get; set; }
}

I would like to be able to write something similar to the above and have settings.Foo read from the file "foo.txt" and settings.Foo = "bar" write to "foo.txt".

Obviously this is a simplified example and I wouldn't do the above in a production application, but there are other examples, like if I wanted Foo to be stored in ASP.net Session state "foo" but I get tired of writing the following code over and over:

public int Foo
{
    get
    {
        if (Session["foo"] != null)
            return Convert.ToInt32(Session["foo"]);
        else
            // Throw an exception or return a default value
    }
    set
    {
        Session["foo"] = value;
    }
}

(Once again this example is simplified and I wouldn't write the above code, actually I'm lying, I have the above code and am working to refactor it, thus this question)

The above example is fine unless you have 50 different session values that all have similar logic. So is there someway I could convert the second property into something similar to the first? (Using attributes and reflection, or maybe some other method?)

like image 664
thelsdj Avatar asked Apr 04 '12 20:04

thelsdj


2 Answers

I know this is not what you (and also I) needed; but this is the closest without using a third party library. You can change the logic for get&set methods and add some cahcing for GetProperty and GetCustomAttributes methods or if you already have a base class you can write get&set methods as static in a helper class. Again not the perfect answer and also may have a bad performance but at least it decreases the code you copy and paste (:

NOTE: It is important to make properties virtual in order to prevent compiler inlining them.

public class SampleClass : SessionObject
{
    [Session(Key = "SS_PROP")]
    public virtual int SampleProperty
    {
        get { return get(); }
        set { set(value); }
    }

    [Session(Key = "SS_PROP2")]
    public virtual string SampleProperty2
    {
        get { return get(); }
        set { set(value); }
    }
}

[AttributeUsage(AttributeTargets.Property)]
public class SessionAttribute : Attribute
{
    public string Key { get; set; }
}

public abstract class SessionObject
{
    Dictionary<string, object> Session = new Dictionary<string, object>();

    protected void set(object value)
    {
        StackFrame caller = new StackFrame(1);
        MethodBase method = caller.GetMethod();
        string propName = method.Name.Substring(4);
        Type type = method.ReflectedType;
        PropertyInfo pi = type.GetProperty(propName);
        object[] attributes = pi.GetCustomAttributes(typeof(SessionAttribute), true);
        if (attributes != null && attributes.Length == 1)
        {
            SessionAttribute ssAttr = attributes[0] as SessionAttribute;
            Session[ssAttr.Key] = value;
        }
    }

    protected dynamic get()
    {
        StackFrame caller = new StackFrame(1);
        MethodBase method = caller.GetMethod();
        string propName = method.Name.Substring(4);
        Type type = method.ReflectedType;
        PropertyInfo pi = type.GetProperty(propName);
        object[] attributes = pi.GetCustomAttributes(typeof(SessionAttribute), true);
        if (attributes != null && attributes.Length == 1)
        {
            SessionAttribute ssAttr = attributes[0] as SessionAttribute;
            if (Session.ContainsKey(ssAttr.Key))
            {
                return Session[ssAttr.Key];
            }
        }
        return default(dynamic);
    }
}
like image 72
Mehmet Ataş Avatar answered Sep 28 '22 08:09

Mehmet Ataş


Another option could be for you is use of PostSharp. You define attributes and it injects an IL in final code, so it's not going to change your source code. Which has its bads and its goods.

This product is not free.

Some Getting started tips.

Hope this helps.

like image 44
Tigran Avatar answered Sep 28 '22 07:09

Tigran