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.
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
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"];
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With