This code sample demonstrates how to copy class properties from one class to another even if they are not the same type. It also demonstrates how to validate a class's required properties dynamically. Both of these can increase your coding productivity especially when dealing with web service versions of your business classes.
PropertyHandler.cs
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Diagnostics;
namespace MyApplication
{
public class PropertyHandler
{
#region Set Properties
public static void SetProperties(PropertyInfo[] fromFields,
PropertyInfo[] toFields,
object fromRecord,
object toRecord)
{
PropertyInfo fromField = null;
PropertyInfo toField = null;
try
{
if (fromFields == null)
{
return;
}
if (toFields == null)
{
return;
}
for (int f = 0; f < fromFields.Length; f++)
{
fromField = (PropertyInfo)fromFields[f];
for (int t = 0; t < toFields.Length; t++)
{
toField = (PropertyInfo)toFields[t];
if (fromField.Name != toField.Name)
{
continue;
}
toField.SetValue(toRecord,
fromField.GetValue(fromRecord, null),
null);
break;
}
}
}
catch (Exception)
{
throw;
}
}
#endregion
#region Set Properties
public static void SetProperties(PropertyInfo[] fromFields,
object fromRecord,
object toRecord)
{
PropertyInfo fromField = null;
try
{
if (fromFields == null)
{
return;
}
for (int f = 0; f < fromFields.Length; f++)
{
fromField = (PropertyInfo)fromFields[f];
fromField.SetValue(toRecord,
fromField.GetValue(fromRecord, null),
null);
}
}
catch (Exception)
{
throw;
}
}
#endregion
}
}
PropertyHandler Sample For Identical Classes
MyClass record = new MyClass();
MyClass newRecord = new MyClass();
PropertyInfo[] fromFields = null;
fromFields = typeof(MyClass).GetProperties();
PropertyHandler.SetProperties(fromFields, record, newRecord);
PropertyHandler Sample For Similar Classes
MyClass record = new MyClass();
MyOtherClass newRecord = new MyOtherClass();
PropertyInfo[] fromFields = null;
PropertyInfo[] toFields = null;
fromFields = typeof(MyClass).GetProperties();
toFields = typeof(MyOtherClass).GetProperties();
PropertyHandler.SetProperties(fromFields,toFields,record, newRecord);
Self Validation Methods
// Some of the code below relies on runtime reflection. Certain aspects
// of reflection are detrimental to performance. Where possible, you
// can create static instances of the reflection results. It will give
// the power without the overhead of using reflection.
// Here is a sample business class layer self validation method.
private bool ValidateSave(CellAlignment record)
{
object[,] properties = null;
List<string> returnMessages = new List<string>();
try
{
// Use the .GetFields() method mentioned later in this sample.
properties = this.GetFields(this.GetType());
if (!record.ValidateRequiredProperties(properties,
returnMessages))
{
for (int i = 0; i < returnMessages.Count; i++)
{
Debug.WriteLine(returnMessages[i]);
}
return false;
}
}
catch (Exception) { throw;}
return true;
}
// This code was extracted from the ADO.NET Code Generator mentioned
// above.
// Here is a sample property to demonstrate how to use the
// ColumnAttributes class. It sets this as being required
// and tells the validator that it is an int data type.
private int cellAlignmentID = 0;
[ColumnAttributes("CellAlignmentID",true,"int")]
public int CellAlignmentID
{
get
{
return cellAlignmentID;
}
set
{
if (value != cellAlignmentID)
{
cellAlignmentID = valuue;
}
}
}
// The ColumnAttributes class itself.
[AttributeUsage(AttributeTargets.Property,AllowMultiple = true)]
public sealed class ColumnAttributes : System.Attribute
{
private string columnName;
private bool isRequired;
private string propertyType;
public string ColumnName
{
get { return columnName; }
}
public bool IsRequired
{
get { return isRequired; }
}
public string PropertyType
{
get { return propertyType; }
}
public ColumnAttributes(string columnNameValue,
bool isRequiredValue,
string propertyTypeValue)
{
columnName = columnNameValue;
isRequired = isRequiredValue;
propertyType = propertyTypeValue;
}
}
// Here is a method we can use to get an array of
// PropertyInfo objects as well as custom attributes.
// Make sure every class has this in method available
// to run on itself. The ADO.NET Code Generator has
// this apart of the CustomAttributes.cs that all
// DataObjects inherit.
public object[,] GetFields(Type t)
{
PropertyInfo[] fields = t.GetProperties();
PropertyInfo field;
Attribute[] attributes;
object[,] structureInfo = new object[fields.Length,2];
try
{
for(int i =0;i<fields.Length;i++)
{
field = fields[i];
attributes = Attribute.GetCustomAttributes(field,
typeof(DataObjects.Tables.ColumnAttributes),
false);
structureInfo[i,0] = field;
structureInfo[i,1] = attributes;
}
}
catch (Exception) { throw; }
return structureInfo;
}
public bool ValidateRequiredProperties(object[,] properties,
List<string> returnMessages)
{
bool returnValue = true;
PropertyInfo property;
Attribute[] attributes;
ColumnAttributes columnAttribute = null;
try
{
if (properties == null)
{
throw new Exception("Please pass in the results of this.GetFields().");
}
if (returnMessages != null)
{
returnMessages.Clear();
}
for (int i = 0; i <= properties.GetUpperBound(0); i++)
{
property = (PropertyInfo)properties[i, 0];
attributes = (Attribute[])properties[i, 1];
foreach (Attribute attribute in attributes)
{
columnAttribute = (ColumnAttributes)attribute;
if (!columnAttribute.IsRequired)
{
continue;
}
// Debug.WriteLine(columnAttribute.ColumnName);
// Debug.WriteLine(property.GetValue(this,null));
if (!this.ValidateRequiredPropertyInfo(columnAttribute,
property))
{
returnValue = false;
if (returnMessages != null)
{
returnMessages.Add(columnAttribute.ColumnName + " is required.");
}
}
}
}
}
catch (Exception) { throw;}
return returnValue;
}
public bool ValidateRequiredProperties(object[,] properties)
{
List<string> returnMessages = null;
try
{
return ValidateRequiredProperties(properties,
returnMessages);
}
catch (Exception) { throw; }
}
public bool ValidateRequiredPropertyInfo(ColumnAttributes columnAttribute,
PropertyInfo property)
{
try
{
switch (columnAttribute.PropertyType.ToLower())
{
case "int":
if ((int)property.GetValue(this,
null) == 0)
{
return false;
}
break;
case "int16":
if ((Int16)property.GetValue(this,
null) == 0)
{
return false;
}
break;
case "int32":
if ((Int32)property.GetValue(this,
null) == 0)
{
return false;
}
break;
case "int64":
if ((Int64)property.GetValue(this,
null) == 0)
{
return false;
}
break;
case "uint":
if ((uint)property.GetValue(this,
null) == 0)
{
return false;
}
break;
case "uint16":
if ((UInt16)property.GetValue(this,
null) == 0)
{
return false;
}
break;
case "uint32":
if ((UInt32)property.GetValue(this,
null) == 0)
{
return false;
}
break;
case "uint64":
if ((UInt64)property.GetValue(this,
null) == 0)
{
return false;
}
break;
case "double":
if ((double)property.GetValue(this,
null) == 0)
{
return false;
}
break;
case "float":
if ((float)property.GetValue(this,
null) == 0)
{
return false;
}
break;
case "single":
if ((Single)property.GetValue(this,
null) == 0)
{
return false;
}
break;
case "string":
if ((string)property.GetValue(this,
null) == String.Empty)
{
return false;
}
break;
case "guid":
if ((Guid)property.GetValue(this,
null) == Guid.Empty)
{
return false;
}
break;
default:
if (property.GetValue(this,
null) == null)
{
return false;
}
break;
}
}
catch (Exception) { throw; }
return true;
}
using System; using System.Collections.Generic; using System.Reflection; using System.Text; using System.Diagnostics; namespace MyApplication { public class PropertyHandler { #region Set Properties public static void SetProperties(PropertyInfo[] fromFields, PropertyInfo[] toFields, object fromRecord, object toRecord) { PropertyInfo fromField = null; PropertyInfo toField = null; try { if (fromFields == null) { return; } if (toFields == null) { return; } for (int f = 0; f < fromFields.Length; f++) { fromField = (PropertyInfo)fromFields[f]; for (int t = 0; t < toFields.Length; t++) { toField = (PropertyInfo)toFields[t]; if (fromField.Name != toField.Name) { continue; } toField.SetValue(toRecord, fromField.GetValue(fromRecord, null), null); break; } } } catch (Exception) { throw; } } #endregion #region Set Properties public static void SetProperties(PropertyInfo[] fromFields, object fromRecord, object toRecord) { PropertyInfo fromField = null; try { if (fromFields == null) { return; } for (int f = 0; f < fromFields.Length; f++) { fromField = (PropertyInfo)fromFields[f]; fromField.SetValue(toRecord, fromField.GetValue(fromRecord, null), null); } } catch (Exception) { throw; } } #endregion } }
MyClass record = new MyClass(); MyClass newRecord = new MyClass(); PropertyInfo[] fromFields = null; fromFields = typeof(MyClass).GetProperties(); PropertyHandler.SetProperties(fromFields, record, newRecord);
MyClass record = new MyClass(); MyOtherClass newRecord = new MyOtherClass(); PropertyInfo[] fromFields = null; PropertyInfo[] toFields = null; fromFields = typeof(MyClass).GetProperties(); toFields = typeof(MyOtherClass).GetProperties(); PropertyHandler.SetProperties(fromFields,toFields,record, newRecord);
// Some of the code below relies on runtime reflection. Certain aspects // of reflection are detrimental to performance. Where possible, you // can create static instances of the reflection results. It will give // the power without the overhead of using reflection. // Here is a sample business class layer self validation method. private bool ValidateSave(CellAlignment record) { object[,] properties = null; List<string> returnMessages = new List<string>(); try { // Use the .GetFields() method mentioned later in this sample. properties = this.GetFields(this.GetType()); if (!record.ValidateRequiredProperties(properties, returnMessages)) { for (int i = 0; i < returnMessages.Count; i++) { Debug.WriteLine(returnMessages[i]); } return false; } } catch (Exception) { throw;} return true; } // This code was extracted from the ADO.NET Code Generator mentioned // above. // Here is a sample property to demonstrate how to use the // ColumnAttributes class. It sets this as being required // and tells the validator that it is an int data type. private int cellAlignmentID = 0; [ColumnAttributes("CellAlignmentID",true,"int")] public int CellAlignmentID { get { return cellAlignmentID; } set { if (value != cellAlignmentID) { cellAlignmentID = valuue; } } } // The ColumnAttributes class itself. [AttributeUsage(AttributeTargets.Property,AllowMultiple = true)] public sealed class ColumnAttributes : System.Attribute { private string columnName; private bool isRequired; private string propertyType; public string ColumnName { get { return columnName; } } public bool IsRequired { get { return isRequired; } } public string PropertyType { get { return propertyType; } } public ColumnAttributes(string columnNameValue, bool isRequiredValue, string propertyTypeValue) { columnName = columnNameValue; isRequired = isRequiredValue; propertyType = propertyTypeValue; } } // Here is a method we can use to get an array of // PropertyInfo objects as well as custom attributes. // Make sure every class has this in method available // to run on itself. The ADO.NET Code Generator has // this apart of the CustomAttributes.cs that all // DataObjects inherit. public object[,] GetFields(Type t) { PropertyInfo[] fields = t.GetProperties(); PropertyInfo field; Attribute[] attributes; object[,] structureInfo = new object[fields.Length,2]; try { for(int i =0;i<fields.Length;i++) { field = fields[i]; attributes = Attribute.GetCustomAttributes(field, typeof(DataObjects.Tables.ColumnAttributes), false); structureInfo[i,0] = field; structureInfo[i,1] = attributes; } } catch (Exception) { throw; } return structureInfo; } public bool ValidateRequiredProperties(object[,] properties, List<string> returnMessages) { bool returnValue = true; PropertyInfo property; Attribute[] attributes; ColumnAttributes columnAttribute = null; try { if (properties == null) { throw new Exception("Please pass in the results of this.GetFields()."); } if (returnMessages != null) { returnMessages.Clear(); } for (int i = 0; i <= properties.GetUpperBound(0); i++) { property = (PropertyInfo)properties[i, 0]; attributes = (Attribute[])properties[i, 1]; foreach (Attribute attribute in attributes) { columnAttribute = (ColumnAttributes)attribute; if (!columnAttribute.IsRequired) { continue; } // Debug.WriteLine(columnAttribute.ColumnName); // Debug.WriteLine(property.GetValue(this,null)); if (!this.ValidateRequiredPropertyInfo(columnAttribute, property)) { returnValue = false; if (returnMessages != null) { returnMessages.Add(columnAttribute.ColumnName + " is required."); } } } } } catch (Exception) { throw;} return returnValue; } public bool ValidateRequiredProperties(object[,] properties) { List<string> returnMessages = null; try { return ValidateRequiredProperties(properties, returnMessages); } catch (Exception) { throw; } } public bool ValidateRequiredPropertyInfo(ColumnAttributes columnAttribute, PropertyInfo property) { try { switch (columnAttribute.PropertyType.ToLower()) { case "int": if ((int)property.GetValue(this, null) == 0) { return false; } break; case "int16": if ((Int16)property.GetValue(this, null) == 0) { return false; } break; case "int32": if ((Int32)property.GetValue(this, null) == 0) { return false; } break; case "int64": if ((Int64)property.GetValue(this, null) == 0) { return false; } break; case "uint": if ((uint)property.GetValue(this, null) == 0) { return false; } break; case "uint16": if ((UInt16)property.GetValue(this, null) == 0) { return false; } break; case "uint32": if ((UInt32)property.GetValue(this, null) == 0) { return false; } break; case "uint64": if ((UInt64)property.GetValue(this, null) == 0) { return false; } break; case "double": if ((double)property.GetValue(this, null) == 0) { return false; } break; case "float": if ((float)property.GetValue(this, null) == 0) { return false; } break; case "single": if ((Single)property.GetValue(this, null) == 0) { return false; } break; case "string": if ((string)property.GetValue(this, null) == String.Empty) { return false; } break; case "guid": if ((Guid)property.GetValue(this, null) == Guid.Empty) { return false; } break; default: if (property.GetValue(this, null) == null) { return false; } break; } } catch (Exception) { throw; } return true; }