5

As a part of my API, I have an abstract BaseEntity class. I would like to provide a way to somehow hook into new properties that are introduced in the descendants of this class. What I was thinking is this:

public class MyEntity : BaseEntity
{
    [DataElement]
    public int NewProperty { get; set; }
}

If I could write an attribute DataElement that would hook in the getter and setter, then my API would be made aware of this property on access.

Is this possible?

UPD: I'll try to explain where this comes from. I have this BaseEntity that does not have any data by itself. Its descendants will declare what data they may hold as properties. I want to be able to iterate through all the data the object has (to store it in the database in a very specific form). One way to do it is reflection. But I thought about doing it via attributes that would register the data whenever the property is accessed.

3

2 Answers 2

6

Of course, it would look similar to the following:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class DataElementAttribute : Attribute 
{ }

You will have to enumerate the properties with reflection to see if the property contains the attribute. (which begs the question, do you really need the attribute).

        Assembly assembly = Assembly.GetExecutingAssembly();
        foreach (Type type in assembly.GetTypes())
        {
            IList<PropertyInfo> properties = type.GetProperties();
            foreach (PropertyInfo pi in properties)
            {
                if (type.IsDefined(typeof(DataElementAttribute), false))
                {
                    // Perform Logic
                }
            }
        }

However injecting Logic into the setter is a different task which would need to be done post compilation: Why is post-compilation code injection a better idea than pre-compilation code injection?

Injecting MSIL is not easy. Take a peek at this example code: http://www.codeproject.com/Articles/37549/CLR-Injection-Runtime-Method-Replacer

Sign up to request clarification or add additional context in comments.

1 Comment

I was thinking that whenever the property gets written to, I also add the data into a protected dictionary. One way to do this is to explicitly call a method inside the property. I thought I could also hook into the setter using an attribute.
1

You could force inheritors to specify how the object should be saved/loaded by adding a couple of abstract methods.

Example, inspired by the ISerializable interface:

public abstract class BaseEntity
{
    public void SaveToDatabase()
    {
        var objectData = new Dictionary<string, object>();
        this.GetObjectData(objectData);
        DatabaseManager.Save(objectData);
    }

    public void LoadFromDatabase(Dictionary<string, object> data)
    {
        this.SetObjectData(data);
    }

    protected abstract void GetObjectData(Dictionary<string, object> data);

    protected abstract void SetObjectData(Dictionary<string, object> data);
}

public class MyEntity : BaseEntity
{
    public int NewProperty { get; set; }

    protected override void GetObjectData(Dictionary<string, object> data)
    {
        data.Add("NewProperty", this.NewProperty);
    }

    protected override void SetObjectData(Dictionary<string, object> data)
    {
        this.NewProperty = (int)data["NewProperty"];
    }
}

2 Comments

The problem with this sort of approach is that it becomes hard to maintain it when adding new data parts.
You could also make the Get/SetObjectData methods virtual instead of abstract, and provide a default implementation that uses reflection to get/set the property values.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.