Click here to Skip to main content
15,885,757 members
Articles / Desktop Programming / WPF

Catel - Part 4 of n: Unit testing with Catel

Rate me:
Please Sign up or sign in to vote.
4.55/5 (10 votes)
28 Jan 2011CPOL11 min read 48.9K   572   11  
This article explains how to write unit tests for MVVM using Catel.
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TypeHelper.cs" company="Catel development team">
//   Copyright (c) 2008 - 2011 Catel development team. All rights reserved.
// </copyright>
// <summary>
//   <see cref="Type" /> helper class.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Catel.Properties;
using log4net;

#if SILVERLIGHT
using Catel.Reflection;
#endif

namespace Catel
{
    /// <summary>
    /// <see cref="Type"/> helper class.
    /// </summary>
    public static class TypeHelper
    {
        #region Variables
        /// <summary>
        /// The <see cref="ILog">log</see> object.
        /// </summary>
        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        #endregion

        #region Methods
        /// <summary>
        /// Determines whether the subclass is of a raw generic type.
        /// </summary>
        /// <param name="generic">The generic.</param>
        /// <param name="toCheck">The type to check.</param>
        /// <returns>
        /// 	<c>true</c> if the subclass is of a raw generic type; otherwise, <c>false</c>.
        /// </returns>
        /// <exception cref="ArgumentNullException">when <paramref name="generic"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">when <paramref name="toCheck"/> is <c>null</c>.</exception>
        /// <remarks>
        /// This implementation is based on this forum thread:
        /// http://stackoverflow.com/questions/457676/c-reflection-check-if-a-class-is-derived-from-a-generic-class
        /// </remarks>
        public static bool IsSubclassOfRawGeneric(Type generic, Type toCheck)
        {
            if (generic == null)
            {
            	throw new ArgumentNullException("generic");
            }

            if (toCheck == null)
            {
            	throw new ArgumentNullException("toCheck");
            }

            while ((toCheck != null) && (toCheck != typeof(object)))
            {
                var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
                if (generic == cur)
                {
                	return true;
                }

                toCheck = toCheck.BaseType;
            }

            return false;
        }

        /// <summary>
        /// Formats a type in the official type description like [typename], [assemblyname].
        /// </summary>
        /// <param name="assembly">Assembly name to format.</param>
        /// <param name="type">Type name to format.</param>
        /// <returns>Type name like [typename], [assemblyname].</returns>
        public static string FormatType(string assembly, string type)
        {
            return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", type, assembly);
        }

        /// <summary>
        /// Formats multiple inner types into one string.
        /// </summary>
        /// <param name="innerTypes">The inner types.</param>
        /// <returns>
        /// string representing a combination of all inner types.
        /// </returns>
        public static string FormatInnerTypes(string[] innerTypes)
        {
            string result = string.Empty;

            for (int i = 0; i < innerTypes.Length; i++)
            {
                result += string.Format(CultureInfo.InvariantCulture, "[{0}]", innerTypes[i]);

                // Postfix a comma if this is not the last
                if (i < innerTypes.Length - 1)
                {
                	result += ",";
                }
            }

            return result;
        }

        /// <summary>
        /// Returns whether a type is nullable or not.
        /// </summary>
        /// <param name="type">Type to check.</param>
        /// <returns>
        /// True if the type is nullable, otherwise false.
        /// </returns>
        public static bool IsTypeNullable(Type type)
        {
            if (type == null)
            {
            	return false;
            }

            if (!type.IsValueType)
            {
            	return true;
            }

            if (Nullable.GetUnderlyingType(type) != null)
            {
            	return true;
            }

            return false;
        }

        /// <summary>
        /// Checks whether the 2 specified objects are equal. This method is better, simple because it also checks boxing so
        /// 2 integers with the same values that are boxed are equal.
        /// </summary>
        /// <param name="object1">The first object.</param>
        /// <param name="object2">The second object.</param>
        /// <returns><c>true</c> if the objects are equal; otherwise <c>false</c>.</returns>
        public static bool AreObjectsEqual(object object1, object object2)
        {
            if ((object1 == null) && (object2 == null))
            {
            	return true;
            }

            if ((object1 == null) || (object2 == null))
            {
            	return false;
            }

            return object1.Equals(object2);
        }

        /// <summary>
        /// Gets the <see cref="PropertyInfo"/> for the specified property.
        /// </summary>
        /// <param name="type">The type that contains the properties.</param>
        /// <param name="property">The property name.</param>
        /// <returns>
        /// 	<see cref="PropertyInfo"/> or <c>null</c> if no property info is found.
        /// </returns>
        public static PropertyInfo GetPropertyInfo(Type type, string property)
        {
            PropertyInfo propertyInfo = type.GetProperty(property, BindingFlags.Public | BindingFlags.Instance);
            if (propertyInfo == null)
            {
            	propertyInfo = type.GetProperty(property, BindingFlags.NonPublic | BindingFlags.Instance);
            }

            if (propertyInfo == null)
            {
                Log.Warn(TraceMessages.CannotFindProperty, property);
            }

            return propertyInfo;
        }
        #endregion

        #region [ object size ]

        /// <summary>
        /// Cache of type sizes.
        /// </summary>
        private static readonly IDictionary<Type, int> TypeSizes = InitializeSizeHelper();

        /// <summary>
        /// Initializes the size helper.
        /// </summary>
        /// <returns>Dictionary containing the type and its size.</returns>
        private static IDictionary<Type, int> InitializeSizeHelper()
        {
            IDictionary<Type, int> rv = new Dictionary<Type, int>();

            rv.Add(typeof(DateTime), 8);
            rv.Add(typeof(Pointer), 8); // Prevent endless loops.
            rv.Add(typeof(long), 8);
            rv.Add(typeof(int), 4);
            rv.Add(typeof(short), 2);
            rv.Add(typeof(ulong), 8);
            rv.Add(typeof(uint), 4);
            rv.Add(typeof(ushort), 2);

            return rv;
        }

        /// <summary>
        /// Determine the size of any object.
        /// </summary>
        /// <param name="obj">The object you want to know the size of.</param>
        /// <returns>A size in bytes, or -1 if the request failed.</returns>
        public static int SizeOf(object obj)
        {
            int sizeValue;

            try
            {
                sizeValue = ReflectiveSizeOf(obj);
            }
            catch
            {
                sizeValue = -1;
            }

            return sizeValue;
        }

        /// <summary>
        /// Determines the reflective size of any object.
        /// </summary>
        /// <param name="obj">The object you want to know the size of.</param>
        /// <returns>A size in bytes, or -1 if the request failed.</returns>
        private static int ReflectiveSizeOf(object obj)
        {
            int size = 0;

            if (obj != null)
            {
                Queue<object> objects = new Queue<object>();
                Queue<object> done = new Queue<object>();

                objects.Enqueue(obj);

                while (objects.Count > 0)
                {
                    object target = objects.Dequeue();
                    int targetSize = -1;

                    done.Enqueue(target);

                    if (target == null)
                    {
                        targetSize = 0;
                    }
                    else
                    {
                        try
                        {
                            Type targetType = target.GetType();

                            if (targetType.IsEnum)
                            {
                                targetType = Enum.GetUnderlyingType(targetType);
                            }

                            if (TypeSizes.ContainsKey(targetType))
                            {
                                if (targetSize == -1)
                                {
                                    targetSize = 0;
                                }

                                targetSize += TypeSizes[targetType];
                            }
                            else
                            {
                                if (targetType.IsValueType)
                                {
                                    // int ts2 = System.Runtime.InteropServices.Marshal.SizeOf(targetType);
                                    targetSize = System.Runtime.InteropServices.Marshal.SizeOf(target);
                                }
                                else
                                {
                                    if (target is Delegate)
                                    {
                                        targetSize += TypeSizes[typeof(Pointer)];
                                    }
                                    else
                                    {
                                        targetSize = -2;
                                    }
                                }
                            }
                        }
                        catch (Exception)
                        {
                            targetSize = -2;
                        }
                    }

                    if (target != null && targetSize < 0)
                    {
                        Type targetType = target.GetType();
                        FieldInfo[] fields = targetType.GetFields(BindingFlags.Instance | BindingFlags.GetField | BindingFlags.Public | BindingFlags.NonPublic);

                        foreach (FieldInfo f in fields)
                        {
                            object fieldValue = f.GetValue(target);

                            if (fieldValue != null && !objects.Contains(fieldValue) && !done.Contains(fieldValue))
                            {
                                objects.Enqueue(fieldValue);
                            }
                        }

                        if (target is IEnumerable)
                        {
                            if (target is string)
                            {
                                string targetAsString = target as string;
                                size += targetAsString.Length;
                            }
                            else
                            {
                                IEnumerable col = target as IEnumerable;

                                foreach (object c in col)
                                {
                                    if (c != null && !objects.Contains(c) && !done.Contains(c))
                                    {
                                        objects.Enqueue(c);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        size += targetSize;
                    }
                }

                objects.Clear();	// Should already be empty.
                done.Clear();
            }

            return size;
        }

        #endregion

        #region TryParseEx

        /// <summary>
        /// Helper class for converting Strings to GUIDs.
        /// </summary>
        public static class Parser
        {
            /// <summary>
            /// Pattern guid tester.
            /// </summary>
            private const string PatternGuidTester = "^[0-9A-F]{8}(-?)[0-9A-F]{4}\\1[0-9A-F]{4}\\1[0-9A-F]{4}\\1[0-9A-F]{12}$";

            /// <summary>
            /// The <see cref="Regex"/> containing the guid tester.
            /// </summary>
            private static readonly Regex RxGuidTester = new Regex(PatternGuidTester, RegexOptions.IgnoreCase | RegexOptions.Singleline);

            /// <summary>
            /// Tries to parse a string to a guid.
            /// </summary>
            /// <param name="input">The string version of the guid. Currently supported layouts dddddddd-dddd-dddd-dddd-dddddddddddd and dddddddddddddddddddddddddddddddd where d is a hexadecimal digit.</param>
            /// <param name="output">When the parse succeeds this is the guid else it is set to Guid.Empty.</param>
            /// <returns>False when the parse failed else true.</returns>
            public static bool TryParseGuid(string input, out Guid output)
            {
                bool hasFailed = string.IsNullOrEmpty(input) || !RxGuidTester.IsMatch(input);

                output = !hasFailed ? new Guid(input) : Guid.Empty;

                return !hasFailed;
            }
        }

        #endregion TryParseEx

        #region Powercast
        #region Typed input and output

        /// <summary>
        /// Tries to Generic cast of a value.
        /// </summary>
        /// <typeparam name="TOutput">Requested return type.</typeparam>
        /// <typeparam name="TInput">The input type.</typeparam>
        /// <param name="value">The value to cast.</param>
        /// <param name="output">The casted value.</param>
        /// <returns>When a cast is succeded true else false.</returns>
        public static bool TryCast<TOutput, TInput>(TInput value, out TOutput output)
        {
            bool success = true;
            Type outputType = typeof(TOutput);
            Type innerType = Nullable.GetUnderlyingType(outputType);

            // Database support...
            if (value == null || Convert.IsDBNull(value))
            {
                output = default(TOutput);

                if (outputType.IsValueType && innerType == null)
                {
                    success = false;
                }
                else
                {
                    // Non-valuetype can contain nill.
                    // (Nullable<T> also)
                    success = true;
                }
            }
            else
            {
                Type inputType = value.GetType();

                if (inputType.IsAssignableFrom(outputType))
                {
                    // Direct assignable
                    success = true; 
                    output = (TOutput)(object)value;
                }
                else
                {
                    output = (TOutput)Convert.ChangeType(value, innerType ?? outputType, CultureInfo.InvariantCulture);
                    success = true;
                }
            }

            return success;
        }

        /// <summary>
        /// Generic cast of a value.
        /// </summary>
        /// <typeparam name="TOutput">Requested return type.</typeparam>
        /// <typeparam name="TInput">The input type.</typeparam>
        /// <param name="value">The value to cast.</param>
        /// <returns>The casted value.</returns>
        public static TOutput Cast<TOutput, TInput>(TInput value)
        {
            TOutput output = default(TOutput);

            if (!TryCast(value, out output))
            {
                string tI = typeof(TInput).FullName;
                string tO = typeof(TOutput).FullName;
                string vl = string.Concat(value);
                string msg = "Failed to cast from '{0}' to '{1}'";

                if (!tI.Equals(vl))
                {
                    if (value == null)
                    {
                        vl = "nill-value";
                    }

                    msg = string.Concat(msg, " for value '{2}'");
                }

                msg = string.Format(msg, tI, tO, vl);
                throw new InvalidCastException(msg);
            }

            return output;
        }

        /// <summary>
        /// Generic cast of a value.
        /// </summary>
        /// <typeparam name="TOutput">Requested return type.</typeparam>
        /// <typeparam name="TInput">The input type.</typeparam>
        /// <param name="value">The value to cast.</param>
        /// <param name="whenNullValue">When unable to cast the incoming value, this value is returned instead.</param>
        /// <returns>The casted value or when uncastable the <paramref name="whenNullValue" /> is returned.</returns>
        public static TOutput Cast<TOutput, TInput>(TInput value, TOutput whenNullValue)
        {
            TOutput output;

            if (!TryCast(value, out output) || output == null)
            {
                output = whenNullValue;
            }

            return output;
        }

        #endregion
        #region Unknown input type / common object input

        /// <summary>
        /// Generic cast of a value.
        /// </summary>
        /// <typeparam name="TOutput">Requested return type.</typeparam>
        /// <param name="input">The object to cast.</param>
        /// <returns>The casted value.</returns>
        public static TOutput Cast<TOutput>(object input)
        {
            return Cast<TOutput, object>(input);
        }

        /// <summary>
        /// Generic cast of a value.
        /// </summary>
        /// <typeparam name="TOutput">Requested return type.</typeparam>
        /// <param name="input">The input.</param>
        /// <param name="whenNullValue">When unable to cast the incoming value, this value is returned instead.</param>
        /// <returns>
        /// The casted value or when uncastable the <paramref name="whenNullValue"/> is returned.
        /// </returns>
        public static TOutput Cast<TOutput>(object input, TOutput whenNullValue)
        {
            return Cast<TOutput, object>(input, whenNullValue);
        }

        #endregion
        #endregion

        #region Reflection helpers

        /// <summary>
        /// Gets a specific property from an object.
        /// </summary>
        /// <typeparam name="TProperty">The type of the property.</typeparam>
        /// <typeparam name="TObject">The type of the object.</typeparam>
        /// <param name="property">The name of the property to get.</param>
        /// <param name="sourceObject">The source object.</param>
        /// <returns>The property.</returns>
        public static TProperty PropertyGet<TProperty, TObject>(string property, TObject sourceObject)
        {
            // Use cache?
            if (string.IsNullOrEmpty(property))
            {
                throw new ArgumentNullException("property", "Parameter is Null or Empty.");
            }

            if (sourceObject == null)
            {
                throw new ArgumentNullException("sourceObject");
            }

            Type objType = typeof(TObject);
            PropertyInfo pi = objType.GetProperty(property, typeof(TProperty), Type.EmptyTypes);

            if (pi == null || !pi.CanRead)
            {
                string msg;

                if (pi == null)
                {
                    msg = "No public {2}-property found with the name '{0}' in type '{1}'";
                }
                else
                {
                    msg = "{2}-property '{0}' in type '{1}' cannot be read.";
                }

                msg = string.Format(msg, property, objType.FullName, typeof(TProperty).Name);

                throw new Exception(msg);
            }

            MethodInfo mi = pi.GetGetMethod();
            object value = mi.Invoke(sourceObject, new object[0]);

            return Cast<TProperty>(value);
        }

        /// <summary>
        /// Gets the property value.
        /// </summary>
        /// <param name="instance">The instance.</param>
        /// <param name="propertyPath">The property path.</param>
        /// <returns>The property value.</returns>
        public static object GetPropertyValue(object instance, string propertyPath)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            if (string.IsNullOrEmpty(propertyPath))
            {
                throw new ArgumentNullException("propertyPath");
            }

            return GetMemberValue(instance.GetType(), instance, propertyPath);
        }

        /// <summary>
        /// This method gives you the ability to read values of private fields of an object.
        /// </summary>
        /// <param name="instance">The instance of the object of which you want to know the private value.</param>
        /// <param name="fieldName">The name of the field you want to know... when you want to know a field of an private object of an object you can use the common OO-notation.</param>
        /// <returns>
        /// The value of the object.
        /// <para />
        /// NOTE: When the Field is not found the object, an exception is thrown.
        /// </returns>
        public static object GetField(object instance, string fieldName)
        {
            Type instanceType = instance.GetType();

            return GetField(instanceType, instance, fieldName);
        }

        /// <summary>
        /// This method gives you the ability to read values of private fields of an object.
        /// </summary>
        /// <param name="typeInterface">The interface use want to use when interpeting the class</param>
        /// <param name="instance">The instance of the object of which you want to know the private value.</param>
        /// <param name="fieldName">The name of the field you want to know... when you want to know a field of an private object of an object you can use the common OO-notation.</param>
        /// <returns>
        /// The value of the object.
        /// <para />
        /// NOTE: When the Field is not found the object, an exception is thrown.
        /// </returns>
        public static object GetField(Type typeInterface, object instance, string fieldName)
        {
            // TODO: Use GetMemberInfo
            int firstIndexOfPeriod = fieldName.IndexOf('.');
            string firstPart = (firstIndexOfPeriod == -1) ? fieldName : fieldName.Substring(0, firstIndexOfPeriod);
            string restPart = (firstIndexOfPeriod == -1) ? null : fieldName.Substring(firstIndexOfPeriod + 1);
            object fieldValue;
            FieldInfo fieldDesc = typeInterface.GetField(firstPart, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField);

            if (fieldDesc == null)
            {
                if (typeInterface.BaseType == null)
                {
                    // TODO: Use an dedicated exception-class
                    throw new Exception("Field not found in object-type (or any base-type).");
                }

                fieldValue = GetField(typeInterface.BaseType, instance, fieldName);
            }
            else
            {
                fieldValue = fieldDesc.GetValue(instance);

                if (restPart != null)
                {
                    fieldValue = GetField(fieldValue, restPart);
                }
            }

            return fieldValue;
        }

        /// <summary>
        /// Gets the member info.
        /// </summary>
        /// <param name="typeInterface">The type interface.</param>
        /// <param name="instance">The instance.</param>
        /// <param name="fieldName">Name of the field.</param>
        /// <returns>The value of the object.</returns>
        private static object GetMemberValue(Type typeInterface, object instance, string fieldName)
        {
            // TODO: Helaas klopt er nu geen r(u)(ee)(k)(t) van....
            // TODO: Validate typeFlag
            int firstIndexOfPeriod = fieldName.IndexOf('.');
            string firstPart = (firstIndexOfPeriod == -1) ? fieldName : fieldName.Substring(0, firstIndexOfPeriod);
            string restPart = (firstIndexOfPeriod == -1) ? null : fieldName.Substring(firstIndexOfPeriod + 1);
            MemberInfo[] memberDesc = typeInterface.GetMember(firstPart, MemberTypes.Field | MemberTypes.Property, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            object memberValue;

            if (memberDesc == null || memberDesc.Length == 0)
            {
                if (typeInterface.BaseType == null)
                {
                    // TODO: Use an dedicated exception-class
                    throw new Exception("Field not found in object-type (or any base-type).");
                }

                memberValue = GetMemberValue(typeInterface.BaseType, instance, fieldName);
            }
            else
            {
                if (memberDesc.Length > 1)
                {
                    throw new NotSupportedException("Too many results.");
                }

                MemberInfo mi = memberDesc[0];

                if (mi is FieldInfo)
                {
                    FieldInfo fi = (FieldInfo)mi;
                    memberValue = fi.GetValue(instance);
                }
                else if (mi is PropertyInfo)
                {
                    PropertyInfo pi = (PropertyInfo)mi;
                    memberValue = pi.GetValue(instance, null);
                }
                else
                {
                    // Currently not supported.
                    throw new NotSupportedException();
                }

                if (restPart != null && memberValue != null)
                {
                    memberValue = GetMemberValue(memberValue.GetType(), memberValue, restPart);
                }
            }

            return memberValue;
        }

        /// <summary>
        /// This method gives you the ability to change values of private fields of an object.
        /// </summary>
        /// <param name="instance">The instance of the object of which you want to change a field-value.</param>
        /// <param name="fieldName">The field-name... when you want to know a field of an private object of an object you can use the common OO-notation.</param>
        /// <param name="value">The value you want to put in the field, WARNING this method does NOT check the types of the objects.</param>
        public static void SetField(object instance, string fieldName, object value)
        {
            Type instanceType = instance.GetType();

            SetField(instanceType, instance, fieldName, value);
        }

        /// <summary>
        /// This method gives you the ability to change values of private fields of an object.
        /// </summary>
        /// <param name="typeInterface">The interface use want to use when interpeting the class</param>
        /// <param name="instance">The instance of the object of which you want to change a field-value.</param>
        /// <param name="fieldName">The field-name... when you want to know a field of an private object of an object you can use the common OO-notation.</param>
        /// <param name="value">The value you want to put in the field, WARNING this method does NOT check the types of the objects.</param>
        public static void SetField(Type typeInterface, object instance, string fieldName, object value)
        {
            int firstIndexOfPeriod = fieldName.IndexOf('.');
            string firstPart = (firstIndexOfPeriod == -1) ? fieldName : fieldName.Substring(0, firstIndexOfPeriod);
            string restPart = (firstIndexOfPeriod == -1) ? null : fieldName.Substring(firstIndexOfPeriod + 1);
            FieldInfo fieldDesc = typeInterface.GetField(firstPart, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField);

            if (fieldDesc == null)
            {
                if (typeInterface.BaseType == null)
                {
                    throw new Exception("Field not found in object-type (or any base-type).");
                }

                SetField(typeInterface.BaseType, instance, fieldName, value);
            }
            else
            {
                if (restPart != null)
                {
                    object fieldValue = fieldDesc.GetValue(instance);
                    SetField(fieldValue, restPart, value);

                    if (fieldValue is ValueType)
                    {
                        fieldDesc.SetValue(instance, fieldValue);
                    }
                }
                else
                {
                    fieldDesc.SetValue(instance, value);
                }
            }
        }

        #endregion

        #region Hash-tool

        /// <summary>
        /// Combine multiple hashcodes in to one.
        /// </summary>
        /// <param name="hashes">An array of hashcodes.</param>
        /// <returns>An 'unique' hashcode.</returns>
        /// <remarks>
        /// Based on System.Web.UI.HashCodeCombiner (use Reflector).
        /// </remarks>
        public static int CombineHash(params int[] hashes)
        {
            if (hashes == null || hashes.Length == 0)
            {
                throw new ArgumentException("Array can't be null or empty.", "hashes");
            }

            int hash = 5381; // 0x1505L

            foreach (int inp in hashes)
            {
                hash = ((hash << 5) + hash) ^ inp;
            }

            // Make sure the hash is not negative
            if (hash < 0)
            {
                hash = hash * -1;
            }

            // Return hash
            return hash;
        }

        #endregion

        #region Dispose helper function
        /// <summary>
        /// Clears all events.
        /// </summary>
        /// <param name="obj">The object.</param>
        public static void ClearAllEvents(object obj)
        {
            // Geen object, geen events.
            if (obj == null)
            {
            	return;
            }

            Type objectType = obj.GetType();

            EventInfo[] eis = objectType.GetEvents();

            // Ga alle events van dit object af.
            foreach (EventInfo ei in eis)
            {
                UnsubscribeAll(obj, ei);
            }
        }

        /// <summary>
        /// Unsubscribes all.
        /// </summary>
        /// <param name="obj">The object.</param>
        /// <param name="ei">The event info.</param>
        private static void UnsubscribeAll(object obj, EventInfo ei)
        {
            if (ei.EventHandlerType.BaseType != typeof(MulticastDelegate))
            {
                // Geen MulticastDelegate => geen event.
                return;
            }

            MethodInfo invoke = ei.EventHandlerType.GetMethod("Invoke");
            if (invoke == null)
            {
                // Geen Invoke-method => geen event.
                return;
            }

            Type objectType = obj.GetType();
            FieldInfo eventField = objectType.GetField(ei.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            if (eventField == null)
            {
            	return;
            }

            // Value van dit Event-field, de feitelijke storage van de delegates.
            object eventValue = eventField.GetValue(obj);
            if (eventValue == null)
            {
            	return;
            }

            // Geregistreerde delegates ophalen.
            MethodInfo getInvocationList = ei.EventHandlerType.GetMethod("GetInvocationList");
            Delegate[] delegates = (Delegate[])getInvocationList.Invoke(eventValue, null);

            // Elke delegate uit het event verwijderen.
            foreach (Delegate handler in delegates)
            {
                ei.RemoveEventHandler(obj, handler);
            }
        }

        /// <summary>
        /// Clears the event.
        /// </summary>
        /// <param name="instance">The object instance.</param>
        /// <param name="eventHandler">The event handler.</param>
        public static void ClearEvent(object instance, object eventHandler)
        {
            if (instance == null)
            {
            	return;
            }

            if (eventHandler == null)
            {
            	return;
            }

            Type etype = eventHandler.GetType();
            if (etype.BaseType != typeof(MulticastDelegate))
            {
                // Geen MulticastDelegate => geen event.
                return;
            }

            MethodInfo invoke = etype.GetMethod("Invoke");
            if (invoke == null)
            {
                // Geen Invoke-method => geen event.
                return;
            }

            const BindingFlags AllInstance = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
            Type instanceType = instance.GetType();

            // Event info zoeken bij de geleverde event-storage
            EventInfo eventInfo = (from fi in instanceType.GetFields(AllInstance)
                                   let fieldvalue = fi.GetValue(instance)
                                   where fieldvalue == eventHandler
                                   select instanceType.GetEvent(fi.Name, AllInstance)).FirstOrDefault();
            if (eventInfo == null)
            {
            	return;
            }

            // Geregistreerde delegates ophalen.
            MethodInfo getInvocationList = etype.GetMethod("GetInvocationList");
            Delegate[] delegates = (Delegate[])getInvocationList.Invoke(eventHandler, null);

            // Elke delegate uit het event verwijderen.
            foreach (Delegate handler in delegates)
            {
                eventInfo.RemoveEventHandler(instance, handler);
            }
        }
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Netherlands Netherlands
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions