Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Using meta-data in .NET
Message
From
25/10/2007 15:28:39
 
 
To
25/10/2007 04:25:20
General information
Forum:
ASP.NET
Category:
Coding, syntax and commands
Miscellaneous
Thread ID:
01262116
Message ID:
01263776
Views:
14
Alex,

here is other sample to you which uses TypeDescriptor to add property at runtime.
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; }
}
>Thank you Andrus. It's going to take me a while to try your code, but it will be very educational.
Andrus
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform