MyControl.AddProperty('MyNewProperty', 'MyDefaultValue')?Oh, wait, that's VFP syntax...
using System; >using System.Windows.Forms; >using System.Collections.Generic; >using System.ComponentModel; >using System.Runtime.CompilerServices; > >static class Program { > [STAThread] > static void Main() { > Customer Customer = new Customer(); > Customer.AddProperty<string>("Name"); > Customer.SetValue("Name", "Alex"); > MessageBox.Show(Customer.GetStringValue("Name")); > } >} > >// Runtime extensible business object >public class Customer : EntityBase<Customer> { > string id; > > public string Id { > get { > return id; > } > set { > id = value; > } > } >} > >// from core library >public abstract class EntityBase<T> : Bag { > public virtual void SetValue(string propertyName, string propertyValue) { > PropertyDescriptor p = TypeDescriptor.GetProperties(typeof(T))[propertyName]; > ITypeDescriptorContext ctx = new SimpleContext(this, p); > object val; > val = p.Converter.ConvertFromString(ctx, propertyValue); > p.SetValue(this, val); > } > > public virtual string GetStringValue(string propertyName) { > PropertyDescriptor p = TypeDescriptor.GetProperties(typeof(T))[propertyName]; > return p.GetValue(this).ToString(); > } >} > >interface IBag { > void OnAfterValueChanged(string propertyName); > void AddHandler(object key, EventHandler value); > void RemoveHandler(object key, EventHandler value); > void OnEvent(object key); > IBagValue GetValue(string propertyName); >} > >interface IBagValue { > void ResetValue(); > bool IsDefaultValue { get;} > object Value { get; set;} > event EventHandler ValueChanged; >} > >interface IBagDefinition { > IBagValue Create(IBag bag); > PropertyDescriptor Property { get;} >} > >sealed class BagDefinition<T> : IBagDefinition { > private readonly PropertyDescriptor property; > public PropertyDescriptor Property { get { return property; } } > private readonly T defaultValue; > public T DefaultValue { get { return defaultValue; } } > public string Name { get { return Property.Name; } } > > IBagValue IBagDefinition.Create(IBag bag) { > return new BagValue<T>(bag, this); > } > > public BagDefinition(string propertyName, Attribute[] attributes) { > defaultValue = default(T); > if (attributes != null) { // check for a default value > foreach (Attribute attrib in attributes) { > DefaultValueAttribute defAttrib = attrib as >DefaultValueAttribute; > if (defAttrib != null) { > defaultValue = (T)defAttrib.Value; > break; > } > } > } > property = new BagPropertyDescriptor(propertyName, attributes); > } > > > internal class BagPropertyDescriptor : PropertyDescriptor { > public BagPropertyDescriptor(string name, Attribute[] attributes) > : base(name, attributes) { } > > > private IBagValue GetBagValue(object component) { > return ((IBag)component).GetValue(Name); > } > > > public override object GetValue(object component) { > return GetBagValue(component).Value; > } > > > public override void SetValue(object component, object value) { > GetBagValue(component).Value = value; > } > > > public override Type ComponentType { > get { return typeof(Bag); } > } > > > public override Type PropertyType { > get { return typeof(T); } > } > > > public override bool IsReadOnly { > get { return false; } > } > > > public override bool CanResetValue(object component) { > return true; > } > > > public override void ResetValue(object component) { > GetBagValue(component).ResetValue(); > } > > > public override bool ShouldSerializeValue(object component) { > return !GetBagValue(component).IsDefaultValue; > } > public override bool SupportsChangeEvents { > get { return true; } > } > > > public override void AddValueChanged(object component, >EventHandler handler) { > GetBagValue(component).ValueChanged += handler; > } > > public override void RemoveValueChanged(object component, > EventHandler handler) { > GetBagValue(component).ValueChanged -= handler; > } > } >} > > >sealed class BagValue<T> : IBagValue, ITypeDescriptorContext { > private T value; > private readonly IBag bag; > void IBagValue.ResetValue() { > Value = Definition.DefaultValue; > } > bool IBagValue.IsDefaultValue { > get { > return EqualityComparer<T>.Default.Equals(Value, > Definition.DefaultValue); > } > } > private readonly BagDefinition<T> definition; > public IBag Bag { get { return bag; } } > public BagDefinition<T> Definition { get { return definition; } } > public BagValue(IBag bag, BagDefinition<T> definition) { > if (bag == null) throw new ArgumentNullException("bag"); > if (definition == null) throw new ArgumentNullException("definition"); > this.bag = bag; > this.definition = definition; > Value = Definition.DefaultValue; > } > > public T Value { > get { return value; } > set { > if (EqualityComparer<T>.Default.Equals(Value, value)) > return; > this.value = value; > Bag.OnAfterValueChanged(Definition.Name); > Bag.OnEvent(Definition); > } > } > > > public event EventHandler ValueChanged { > add { Bag.AddHandler(Definition, value); } > remove { Bag.RemoveHandler(Definition, value); } > } > > > object IBagValue.Value { > get { return Value; } > set { Value = (T)value; } > } > > > IContainer ITypeDescriptorContext.Container { > get { > return null; > } > } > object ITypeDescriptorContext.Instance { get { return Bag; } } > void ITypeDescriptorContext.OnComponentChanged() { > Bag.OnAfterValueChanged(Definition.Name); > } > bool ITypeDescriptorContext.OnComponentChanging() { return true; } > PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor { > get { return Definition.Property; } > } > object IServiceProvider.GetService(Type serviceType) { > return null; > } >} > > >public /*sealed*/ class Bag : IBag, INotifyPropertyChanged { > > private EventHandlerList events; > void IBag.AddHandler(object key, EventHandler handler) { > AddHandler(key, handler); > } > void IBag.RemoveHandler(object key, EventHandler handler) { > RemoveHandler(key, handler); > } > void IBag.OnEvent(object key) { > OnEvent(key); > } > private void AddHandler(object key, Delegate handler) { > if (handler == null) return; > if (events == null) events = new EventHandlerList(); > events.AddHandler(key, handler); > } > private void RemoveHandler(object key, Delegate handler) { > if (events == null || handler == null) return; > events.RemoveHandler(key, handler); > } > private void OnEvent(object key) { > if (events == null) return; > EventHandler handler = events[key] as EventHandler; > if (handler != null) handler(this, EventArgs.Empty); > } > public event PropertyChangedEventHandler PropertyChanged { > add { AddHandler(EVENT_PropertyChanged, value); } > remove { RemoveHandler(EVENT_PropertyChanged, value); } > } > private static readonly object EVENT_PropertyChanged = new object(); > private void OnPropertyChanged(string propertyName) { > if (events == null) return; > PropertyChangedEventHandler handler = events[EVENT_PropertyChanged] as >PropertyChangedEventHandler; > if (handler != null) handler(this, new >PropertyChangedEventArgs(propertyName)); > } > > > void IBag.OnAfterValueChanged(string propertyName) { > OnPropertyChanged(propertyName); > } > > > IBagValue IBag.GetValue(string propertyName) { > return GetValue(propertyName); > } > > > private readonly Dictionary<string, IBagValue> values = > new Dictionary<string, IBagValue>(StringComparer.InvariantCulture); > > > private IBagValue GetValue(string propertyName) { > lock (values) { > IBagValue value; > if (!values.TryGetValue(propertyName, out value)) { > value = CreateValue(this, propertyName); > values.Add(propertyName, value); > } > return value; > } > } > > > static readonly Dictionary<string, IBagDefinition> defintions = > new Dictionary<string, >IBagDefinition>(StringComparer.InvariantCulture); > > > public static PropertyDescriptor AddProperty<T>(string propertyName, >params Attribute[] attributes) { > BagDefinition<T> def = new BagDefinition<T>(propertyName, attributes); > lock (defintions) { > defintions.Add(propertyName, def); > BagDescriptionProvider.ResetProperties(); > } > return def.Property; > } > > > internal static PropertyDescriptorCollection GetProperties() { > lock (defintions) { > PropertyDescriptor[] props = new PropertyDescriptor[defintions.Count]; > int i = 0; > foreach (IBagDefinition def in defintions.Values) { > props[i++] = def.Property; > } > return new PhantomPropertyDescriptorCollection(props, false); > } > } > > > internal sealed class PhantomPropertyDescriptorCollection : >PropertyDescriptorCollection { > > > public PhantomPropertyDescriptorCollection(PropertyDescriptor[] >properties, bool readOnly) > : base(properties, readOnly) { > } > > > public override PropertyDescriptor Find(string name, bool ignoreCase) { > PropertyDescriptor prop = base.Find(name, ignoreCase); > if (prop == null) { > prop = AddProperty<object>(name); > Add(prop); > } > return prop; > } > } > > > static IBagValue CreateValue(IBag bag, string propertyName) { > lock (defintions) { > return defintions[propertyName].Create(bag); > } > } > > > public Bag() { } > > static Bag() { > BagDescriptionProvider.Initialize(); > } >} > > >sealed class BagDescriptionProvider : TypeDescriptionProvider { > static readonly BagTypeDescriptor descriptor; > > [MethodImpl(MethodImplOptions.NoInlining)] > internal static void Initialize() { } // to force static ctor > static BagDescriptionProvider() { > ICustomTypeDescriptor parent = >TypeDescriptor.GetProvider(typeof(Bag)).GetTypeDescriptor(typeof(Bag)); > descriptor = new BagTypeDescriptor(parent); > TypeDescriptor.AddProvider(new BagDescriptionProvider(), typeof(Bag)); > } > public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, >object instance) { > return descriptor; > } > > > internal static void ResetProperties() { > descriptor.ResetProperties(); > } >} > > >sealed class BagTypeDescriptor : CustomTypeDescriptor { > public BagTypeDescriptor(ICustomTypeDescriptor parent) > : base(parent) { > if (parent == null) throw new ArgumentNullException("parent"); > } > private PropertyDescriptorCollection properties; > internal void ResetProperties() { > properties = null; > } > public override PropertyDescriptorCollection GetProperties(Attribute[] >attributes) { > return GetProperties(); > } > public override PropertyDescriptorCollection GetProperties() { > if (properties == null) { > properties = Bag.GetProperties(); > } > return properties; > } >} > > > > >[ImmutableObject(true)] >class SimpleContext : ITypeDescriptorContext { > readonly object instance; > readonly PropertyDescriptor property; > > internal SimpleContext(object instance, PropertyDescriptor > property) { > this.instance = instance; > this.property = property; > } > > public IContainer Container { get { return null; } } > public object Instance { get { return instance; } } > public void OnComponentChanged() { } > public bool OnComponentChanging() { return true; } > > public PropertyDescriptor PropertyDescriptor { > get { > return property; > } > } > > public object GetService(Type serviceType) { return null; } >}>