![]() |
Languages »
C# »
How To
Intermediate
License: The Code Project Open License (CPOL)
How To Work Around Passing a Property by ReferenceBy Yang YuHow to work around passing a property by reference using delegates and wrapper class. |
C#, .NET, Dev, Design
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
This article will explain how to work around passing a .NET property similar to passing by ref (or out) parameter. This will often be useful when you would like to alter the actual property pointer. This method is purely for the purpose of having this workaround and not for performance improvement. Since this method uses reflection, it will have some minor overhead.
I hope you will enjoy this article.
When something is passed by ref, its pointer is passed so functions using it will have direct access to the pointer for alteration. The challenge is to pass a property by ref. However, properties are translated into two functions when compiled: the get function and set function. Unlike other functions, the framework does not expose these functions at design time which limits one from accessing their delegates.
Thanks to Alois Kraus for the original idea:
In order to access the property by ref, one must attempt to access the get and set delegate. We can accomplish this by using reflection. The PropertyInfo class contains the GetValue, and SetValue functions which then can be wrapped in a function to simulate the get and set delegates. We can get this by calling the GetProperty function of a given type.
Consider the class:
/// <summary>
/// Used as a wrapper class for passing a property
/// </summary>
/// <typeparam name="T">The type of the property return value</typeparam>
public class PropertyInvoker<T>
{
private PropertyInfo propInfo;
private object obj;
/// <summary>
/// Construct an property Invoker
/// </summary>
/// <param name="PropertyName">the property of an object we want to access</param>
/// <param name="o">the object</param>
public PropertyInvoker(string PropertyName, object o)
{
// set the instance object
this.obj = o;
// get the property information and check weather the type matches T
this.propInfo = o.GetType().GetProperty(PropertyName, typeof(T));
}
/// <summary>
/// Wrapping the get and set into a property
/// </summary>
public T Property
{
get
{
return (T) propInfo.GetValue(obj, null);
}
set
{
propInfo.SetValue(obj, value, null);
}
}
/// <summary>
/// Wrapping the get function
/// </summary>
/// <returns></returns>
public T GetProperty()
{
return this.Property;
}
/// <summary>
/// Wrapping the set function
/// </summary>
/// <param name="value"></param>
public void SetProperty(T value)
{
this.Property = value;
}
}
The PropertyInvoker<T> class allows you to wrap a given property of an object, then you can pass this class into another function similar to by ref since you will now gain direct access to the property itself.
Consider the below class Person which contains properties that are objects, arrays, and primitive types.
/// <summary>
/// describes a person
/// </summary>
public class Person
{
// object
protected String _fullName;
protected Person _father;
protected Person _mother;
// primitive
protected int _age;
// arrays
protected Person[] _children;
public String FullName
{
get {
return this._fullName;
}
set {
this._fullName = value;
}
}
public Person Father
{
get {
return this._father;
}
set {
this._father = value;
}
}
public Person Mother
{
get {
return this._mother;
}
set {
this._mother = value;
}
}
public int Age
{
get {
return this._age;
}
set {
this._age = value;
}
}
public Person[] Children
{
get {
return this._children;
}
set {
this._children = value;
}
}
/// <summary>
/// Default constructor
/// </summary>
/// <param name="Father"></param>
/// <param name="Mother"></param>
/// <param name="FullName"></param>
/// <param name="Age"></param>
/// <param name="Children"></param>
public Person(Person Father, Person Mother,
String FullName, int Age, params Person[] Children)
{
this._father = Father;
this._mother = Mother;
this._fullName = FullName;
this._age = Age;
this._children = Children;
}
/// <summary>
/// Create a person
/// </summary>
/// <param name="FullName"></param>
/// <param name="Age"></param>
public Person(String FullName, int Age)
:this(null, null, FullName, Age)
{
}
}
Normally, it is enough to pass the person object to perform functionalities on the person object. However, sometimes it is required to perform an action on a property rather than the object itself. This means that the function is performed on the Type of the property such as a String manipulation, or an Array manipulation.
Normal by ref requires the pointer of the array:
..
// by ref resize of an array
Person[] children = new Person[] {new Person("Yang Yu", 30)};
// resize this array
Array.Resize<T>(ref children,2);
children[1] = new Person("Kendra Harwood", 28);
..
The above code has taken a normal array and resized it with by ref function which really constructs a new array and reassigns the pointer of children to that bigger array.
But if we want to perform this on the Children property of a Person, we really cannot pass the property in since it is an function, not a variable. This is where PropertyWrapper comes in handy.
..
public static void Resize<T>(PropertyInvoker<T[]> pArray, int newSize)
{
// pre:
if (pArray == null) return;
// get the property value
T[] array = pArray.Property;
// perform by ref functionalities
Array.Resize<T>(ref array, newSize);
// set the property
pArray.Property = array;
}
..
Person me = new Person("Yang Yu", 30);
me.Children = new Person[] {new Person("Raine Yu", 1)};
// call the resize using a property wrapper on the children property
Resize<Person>(new PropertyInvoker<Person[]>("Children", me), 2);
// set resized array
me.Children[1] = new Person("Josh Yu", 2);
We can use the GetProperty and SetProperty function of PropertyInvoker as delegates:
public delegate string GetDelegate();
public delegate void SetDelegate(string value);
Consider the following overloaded functions:
..
public static void ReverseString(PropertyInvoker<String> strProperty)
{
// overload with the get property delegate
ReverseString(strProperty.GetProperty, strProperty.SetProperty);
}
public static void ReverseString(GetDelegate get, SetDelegate set)
{
// invoke the get property method
String str = get.Invoke();
// call actual str reverse function
set.Invoke(ReverseString(str));
}
public static String ReverseString(string str)
{
if (str.Length < 2) return str;
char start = str[0], end = str[str.Length-1];
// reverse inner
return string.Concat(end, ReverseString
(str.Substring(1, str.Length - 2)), start);
}
..
The overloaded ReverseString takes the delegates as a parameter, which we use the get property and set property of the PropertyInvoker object. For example:
ReverseString(new PropertyInvoker<string>("FullName", new Person("Yang Yu", 33)));
I hope this article has helped in your understanding of some design patterns around delegates and property passing as a parameter.
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 27 Nov 2008 Editor: Deeksha Shenoy |
Copyright 2008 by Yang Yu Everything else Copyright © CodeProject, 1999-2010 Web20 | Advertise on the Code Project |