![]() |
Languages »
C# »
General
Intermediate
Dynamic Properties implementation using C# genericsBy SteveLi-CellbiDynamic properties implementation using C# generics |
C# 2.0, Windows, .NET 2.0VS2005, Dev
|
||||||||
|
Advanced Search |
|
|
|
||||||||||||||||
Some programming tasks require dynamic nature of properties exposed by an object. E.g. it might be needed to access object property by a given key, it might be needed to get all object properties and iterate over them. Dynamic properties are useful when you need to manage them at runtime, when your object is already instantiated. In this article we are going to create simple implementation of dynamic properties using C# programming language. We'll use generics for our dynamic properties to make the implementation more flexible and to avoid boxing operations when value types are used for underlying property values.
First of all let's define what we need from a dynamic property. Generally speaking dynamic property should allow us to get or set value associated with it if any. Dynamic property may also be complex and may contain child dynamic properties, thus forming complex property tree, so we will also need methods to add or remove child dynamic properties and method to check if child property exists. For most tasks it's ok to reference dynamic property by its string name, so we will use string parameter to reference child dynamic properties.
Here is the list of basic functionality we'll need:
This is a general set of operations we will create inside our dynamic property abstract class. In this article we will not cover methods to access a collection of all child dynamic properties, however it doesn't look to hard to implement this, so we'll leave this implementation as an exercise.
Here is the C# code for the DynamicProperty abstract class:
/// <summary />
/// Abstract class for all dynamic properties.
/// </summary />
public abstract class DynamicProperty<T>
{
// public methods...
/// <summary />
/// Gets value of child property with the given name.
/// </summary />
/// <typeparam name="TValue" />The value type of dynamic property.</typeparam />
/// The name of the property to get.
public abstract TValue GetValue<TValue>(string name);
/// <summary />
/// Sets value of child property with the given name.
/// </summary />
/// <typeparam name="TValue" />The value type of dynamic property.</typeparam />
/// The name of the property to get.
/// The value to set.
public abstract void SetValue<TValue>(string name, TValue value);
/// <summary />
/// Returns true if there is a child property
/// with the given name inside this dynamic property.
/// </summary />
/// The name of the property to check.
public abstract bool HasProperty(string name);
/// <summary />
/// Adds child property to this dynamic property.
/// </summary />
/// <typeparam name="TValue" />The value type of dynamic property.</typeparam />
/// The property to add.
public abstract void AddProperty<TValue>(string name,
DynamicProperty<TValue> property);
/// <summary />
/// Removes child property from this dynamic property.
/// </summary />
/// The name of the property to remove.
public abstract void RemoveProperty(string name);
/// <summary />
/// Gets child dynamic property with the given name.
/// </summary />
/// <typeparam name="TValue" />The value type of dynamic property.</typeparam />
/// The name of the child property to get.
public abstract DynamicProperty<TValue> GetProperty<TValue>(string name);
// public properties...
/// <summary />
/// Gets or sets value of this property.
/// </summary />
public abstract T Value
{
get;
set;
}
}
Note that we are using generic abstract class with T generic type parameter for the property value type. This type parameter is only used as a return type of Value abstract property, and there is no field with T type inside DynamicProperty class, so T type parameter will be needed for descendants. DynamicProperty class defines several abstract methods for adding or removing child dynamic properties. GetValue and SetValue methods can be used to access value of a child property with the specified name. All methods for child property manipulation have TValue generic type parameter (except for HasProperty method, since it just needs only child property name).
DynamicProperty class is not useful by itself as it contains only abstract methods, we can do nothing yet. So we need to define simple DynamicProperty descendant to represent leaf dynamic property: SimpleProperty. SimpleProperty doesn't have any child properties and doesn't allow adding or removing them, instead it only has a value.
Here is the C# code for the SimpleProperty class:
/// <summary />
/// Simple dynamic property.
/// </summary />
public class SimpleProperty<T> : DynamicProperty<T>
{
T _value;
// constructors...
public SimpleProperty(T value)
{
_value = value;
}
// public methods...
public override TValue GetValue<TValue>(string name)
{
throw new
InvalidOperationException("Can't get property value.");
}
public override void SetValue<TValue>(string name, TValue value)
{
throw new
InvalidOperationException("Can't set property value.");
}
public override bool HasProperty(string name)
{
return false;
}
public override void AddProperty<TValue>(string name,
DynamicProperty<TValue> property)
{
throw new
InvalidOperationException("Can't add child properties.");
}
public override void RemoveProperty(string name)
{
throw new
InvalidOperationException("Can't remove child properties.");
}
public override DynamicProperty<TValue> GetProperty<TValue>
(string name)
{
throw new
InvalidOperationException("Can't get child properties.");
}
// public properties...
public override T Value
{
get { return _value; }
set { _value = value; }
}
}
Now we have an ability to create simple dynamic property and assign a value to it. Let's try to create simple properties with string, boolean and integer value types, here is the sample code:
// String property:
DynamicProperty<string> stringProperty =
new SimpleProperty<string>("StringValue");
stringProperty.Value = "Hello";
Console.WriteLine("String property value: {0}", stringProperty.Value);
// Boolean property:
DynamicProperty<bool> boolProperty = new SimpleProperty<bool>(false);
boolProperty.Value = true;
Console.WriteLine("Boolean property value: {0}",
boolProperty.Value);
// Integer property:
DynamicProperty<int> intProperty = new SimpleProperty<int>(20);
intProperty.Value = 100;
Console.WriteLine("Integer property value: {0}", intProperty.Value);
The sample above is pretty clear: each property has its own type and value passed inside simple property constructor. Value is used to get or set associated property value. Simple property is basic implementation of dynamic property and it is not very useful alone. Again we are going to create another descendant of the DynamicProperty abstract class to support child dynamic properties.
The most interesting part of this article starts here as complex dynamic property class contains core implementation of our dynamic properties concept. I should mention that the same concept we used to represent dynamic properties of text element and formatting objects inside our product for text document text manipulation. Complex property class overrides abstract methods of its ancestor class and adds implementation to support child dynamic properties. We will use System.Collections.Generic.Dictionary
Here is the C# code for the ComplexProperty class:
/// <summary>
/// Complex dynamic property implementation.
/// </summary>
public class ComplexProperty<T> : DynamicProperty<T>
{
Dictionary<string, object> _properties;
// constructors...
public ComplexProperty()
{
}
// private properties...
Dictionary<string, object> Properties
{
get
{
if (_properties == null)
_properties = new Dictionary<string, object>();
return _properties;
}
}
// public methods...
public override TValue GetValue<TValue>(string name)
{
DynamicProperty<TValue> property = GetProperty<TValue>(name);
if (property != null)
return property.Value;
return default(TValue);
}
public override void SetValue<TValue>(string name, TValue value)
{
DynamicProperty<TValue> property = GetProperty<TValue>(name);
if (property != null)
property.Value = value;
}
public override bool HasProperty(string name)
{
return _properties == null ? false : Properties.ContainsKey(name);
}
public override void AddProperty<TValue>(string name,
DynamicProperty<TValue> property)
{
if (HasProperty(name))
throw new
InvalidOperationException("Can't add property.");
Properties.Add(name, property);
}
public override void RemoveProperty(string name)
{
Properties.Remove(name);
}
public override DynamicProperty<TValue> GetProperty<TValue>
(string name)
{
if (!HasProperty(name))
throw new
InvalidOperationException("Can't get property.");
DynamicProperty<TValue> property = Properties[name] as
DynamicProperty<TValue>;
if (property == null)
throw new
InvalidOperationException("Invalid type specified.");
return property;
}
// public properties...
public override T Value
{
get { return default(T); }
set { }
}
}
Note that ComplexProperty doesn't have any value associated with it, so when creating complex property we will use object type as generic type argument (it is also possible to declare ComplexPoperty class without generic type parameters, we'll leave this as an exercise). Inside GetValue and SetValue methods we call GetProperty method first and then get or set underlying property value. We can use complex properties together with simple properties to build complex dynamic property trees. Let's try to create complex dynamic property with three simple child properties from the example above:
// Create complex dynamic property and add child properties:
DynamicProperty<object> complexProperty = new ComplexProperty<object>();
complexProperty.AddProperty("StringProperty", stringProperty);
complexProperty.AddProperty("BooleanProperty", boolProperty);
complexProperty.AddProperty("IntegerProperty", intProperty);
// We can get or set value of child properties now:
complexProperty.SetValue<string>("StringProperty",
"Child String Value");
Console.WriteLine("Complex property child string: {0}",
complexProperty.GetValue<string>("StringProperty"));
complexProperty.SetValue<bool>("BooleanProperty", false);
Console.WriteLine("Complex property child booean: {0}",
complexProperty.GetValue<bool>("BooleanProperty"));
complexProperty.SetValue<int>("IntegerProperty", 200);
Console.WriteLine("Complex property child integer: {0}",
complexProperty.GetValue<int>("IntegerProperty"));
In the example above we create an instance of ComplexProperty class and then add child dynamic properties. Then we can use SetValue and GetValue methods to easily access child property values. Note that AddProperty method calls do not have type arguments specified, this is possible because C# compiler uses type inference to determine which type to use for TValue generic type parameter.
Simple and complex dynamic properties can be used to dynamically create property trees using AddProperty and RemoveProperty methods. However, we found that it is good idea to expose dynamic properties as fixed via class properties when it is known that properties won't change at runtime. E.g. for customer class we can say for sure that FirstName and LastName properties won't be ever removed from customer data type, so it makes sense to expose these dynamic properties. Here is the C# code example:
/// <summary>
/// Customer properties.
/// </summary>
public class CustomerDetails : ComplexProperty<object>
{
// constructors...
public CustomerDetails()
{
AddProperty("FirstName",
new SimpleProperty<string>(String.Empty));
AddProperty("LastName",
new SimpleProperty<string>(String.Empty));
}
// public properties...
public string FirstName
{
get { return GetValue<string>("FirstName"); }
set { SetValue<string>("FirstName", value); }
}
public string LastName
{
get { return GetValue<string>("LastName"); }
set { SetValue<string>("LastName", value); }
}
}
In the example above we expose FirstName and LastName string properties, but we call GetValue and SetValue methods inside getter and setter of these properties. This makes it easy to work with CustomerDetails class without even knowing that FirtName and LastName properties are dynamic properties.
In this article we've implemented a simple dynamic properties concept using C# generic classes. Dynamic property is very flexible concept and can be used when you need to have a class with dynamic nature.
There is still functionality left behind the scope of this article, e.g. Typed Relationship, Dynamic Property Knowledge Level and Extrinsic concepts. For related reading we would recommend "Dealing with Properties" article by Martin Fowler.
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 30 Oct 2007 Editor: |
Copyright 2007 by SteveLi-Cellbi Everything else Copyright © CodeProject, 1999-2009 Web16 | Advertise on the Code Project |