Created
July 1, 2011 20:04
-
-
Save radleta/1059288 to your computer and use it in GitHub Desktop.
Helper Classes to Copy Properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Web; | |
using System.Reflection; | |
namespace Helpers | |
{ | |
/// <summary> | |
/// Used by the <see cref="PropertyHelper.CopyProperties"/> method to | |
/// know which properties to skip. | |
/// </summary> | |
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] | |
public sealed class IgnorePropertiesAttribute : Attribute | |
{ | |
/// <summary> | |
/// Initialize a new instance of the class. | |
/// </summary> | |
/// <param name="ignoredPropertyNames"></param> | |
public IgnorePropertiesAttribute(params string[] ignoredPropertyNames) | |
{ | |
this.IgnoredPropertyNames = new List<string>(ignoredPropertyNames); | |
} | |
/// <summary> | |
/// The list of names of the properties to ignore. | |
/// </summary> | |
public List<string> IgnoredPropertyNames { get; private set; } | |
} | |
/// <summary> | |
/// Helper methods for properties. | |
/// </summary> | |
public static class PropertyHelper | |
{ | |
/// <summary> | |
/// Copies all the properties from the source to the destination. If they do not have | |
/// matching properties, you must use the <see cref="IgnoredPropertyNamesAttribute"/> | |
/// to destinate which properties should be skipped. | |
/// </summary> | |
/// <typeparam name="SOURCE_TYPE">The source type.</typeparam> | |
/// <typeparam name="DESTINATION_TYPE">The destination type.</typeparam> | |
/// <param name="source">The source instance to copy the data FROM.</param> | |
/// <param name="destination">The destination instance to copy the data TO.</param> | |
public static void CopyProperties(object source, object destination) | |
{ | |
if (source == null) | |
{ | |
throw new System.ArgumentNullException("source"); | |
} | |
if (destination == null) | |
{ | |
throw new System.ArgumentNullException("destination"); | |
} | |
Type sourceType = source.GetType(); | |
Type destType = destination.GetType(); | |
var ignoredProperties = new List<string>(); | |
// get ignored properties on the source type | |
var ignorePropertiesAttrs = sourceType.GetCustomAttributes(typeof(IgnorePropertiesAttribute), true); | |
if (ignorePropertiesAttrs.Length > 0 && ignorePropertiesAttrs[0] is IgnorePropertiesAttribute) | |
ignoredProperties.AddRange((ignorePropertiesAttrs[0] as IgnorePropertiesAttribute).IgnoredPropertyNames); | |
// get ignored properties from the destination type | |
ignorePropertiesAttrs = destType.GetCustomAttributes(typeof(IgnorePropertiesAttribute), true); | |
if (ignorePropertiesAttrs.Length > 0 && ignorePropertiesAttrs[0] is IgnorePropertiesAttribute) | |
ignoredProperties.AddRange((ignorePropertiesAttrs[0] as IgnorePropertiesAttribute).IgnoredPropertyNames); | |
var sourceProperties = new List<PropertyInfo>(sourceType.GetProperties()); | |
sourceProperties = sourceProperties.FindAll(prop => !ignoredProperties.Contains(prop.Name) && prop.CanRead); | |
var destProperties = new List<PropertyInfo>(destType.GetProperties()); | |
destProperties = destProperties.FindAll(prop => !ignoredProperties.Contains(prop.Name) && prop.CanWrite); | |
var destPropertyDictionary = destProperties.ToDictionary<PropertyInfo, string>(prop => prop.Name); | |
// validate the source properties exist on destination before we start modifying the destination | |
var missingPropertiesText = new System.Text.StringBuilder(); | |
foreach (var sourceProperty in sourceProperties) | |
{ | |
if (!destPropertyDictionary.ContainsKey(sourceProperty.Name)) | |
{ | |
if (missingPropertiesText.Length > 0) missingPropertiesText.Append(", "); | |
missingPropertiesText.Append(sourceProperty.Name); | |
} | |
} | |
// blow up if they are missing | |
if (missingPropertiesText.Length>0) | |
throw new System.ArgumentOutOfRangeException("destination", destType.FullName, string.Format("Destination type does not have all the expected properties. Either the properties must exist or you must use the IgnorePropertiesAttribute and skip the missing properties. This is to be explicit and ensure the data is copied. Missing Properties = {0}", missingPropertiesText)); | |
// copy all properties from the source to the destination | |
foreach (var sourceProperty in sourceProperties) | |
{ | |
var destProperty = destPropertyDictionary[sourceProperty.Name]; | |
object sourceValue = sourceProperty.GetValue(source, null); | |
destProperty.SetValue(destination, sourceValue, null); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment