using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.SqlTypes; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; using BLToolkit.Common; using BLToolkit.ComponentModel; using BLToolkit.EditableObjects; using BLToolkit.Mapping; using BLToolkit.TypeBuilder; using BLToolkit.TypeBuilder.Builders; using JetBrains.Annotations; namespace BLToolkit.Reflection { public delegate object NullValueProvider(Type type); public delegate bool IsNullHandler (object obj); [DebuggerDisplay("Type = {Type}, OriginalType = {OriginalType}")] public abstract class TypeAccessor : ICollection, ITypeDescriptionProvider { #region Protected Emit Helpers protected MemberInfo GetMember(int memberType, string memberName) { const BindingFlags allInstaceMembers = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; MemberInfo mi; switch (memberType) { case 1: mi = Type.GetField (memberName, allInstaceMembers); break; case 2: mi = Type. GetProperty(memberName, allInstaceMembers) ?? OriginalType.GetProperty(memberName, allInstaceMembers); break; default: throw new InvalidOperationException(); } return mi; } protected void AddMember(MemberAccessor member) { if (member == null) throw new ArgumentNullException("member"); _members.Add(member); _memberNames.Add(member.MemberInfo.Name, member); } #endregion #region CreateInstance [DebuggerStepThrough] public virtual object CreateInstance() { throw new TypeBuilderException(string.Format( "The '{0}' type must have public default or init constructor.", OriginalType.Name)); } [DebuggerStepThrough] public virtual object CreateInstance(InitContext context) { return CreateInstance(); } [DebuggerStepThrough] public object CreateInstanceEx() { return _objectFactory != null? _objectFactory.CreateInstance(this, null): CreateInstance((InitContext)null); } [DebuggerStepThrough] public object CreateInstanceEx(InitContext context) { return _objectFactory != null? _objectFactory.CreateInstance(this, context): CreateInstance(context); } #endregion #region ObjectFactory private IObjectFactory _objectFactory; public IObjectFactory ObjectFactory { get { return _objectFactory; } set { _objectFactory = value; } } #endregion #region Copy & AreEqual internal static object CopyInternal(object source, object dest, TypeAccessor ta) { bool isDirty = false; IMemberwiseEditable sourceEditable = source as IMemberwiseEditable; IMemberwiseEditable destEditable = dest as IMemberwiseEditable; if (sourceEditable != null && destEditable != null) { foreach (MemberAccessor ma in ta) { ma.CloneValue(source, dest); if (sourceEditable.IsDirtyMember(null, ma.MemberInfo.Name, ref isDirty) && !isDirty) destEditable.AcceptMemberChanges(null, ma.MemberInfo.Name); } } else { foreach (MemberAccessor ma in ta) ma.CloneValue(source, dest); } return dest; } public static object Copy(object source, object dest) { if (source == null) throw new ArgumentNullException("source"); if (dest == null) throw new ArgumentNullException("dest"); TypeAccessor ta; Type sType = source.GetType(); Type dType = dest. GetType(); if (TypeHelper.IsSameOrParent(sType, dType)) ta = GetAccessor(sType); else if (TypeHelper.IsSameOrParent(dType, sType)) ta = GetAccessor(dType); else throw new ArgumentException(); return CopyInternal(source, dest, ta); } public static object Copy(object source) { if (source == null) throw new ArgumentNullException("source"); TypeAccessor ta = GetAccessor(source.GetType()); return CopyInternal(source, ta.CreateInstanceEx(), ta); } public static bool AreEqual(object obj1, object obj2) { if (ReferenceEquals(obj1, obj2)) return true; if (obj1 == null || obj2 == null) return false; TypeAccessor ta; Type sType = obj1.GetType(); Type dType = obj2.GetType(); if (TypeHelper.IsSameOrParent(sType, dType)) ta = GetAccessor(sType); else if (TypeHelper.IsSameOrParent(dType, sType)) ta = GetAccessor(dType); else return false; foreach (MemberAccessor ma in ta) if ((!Equals(ma.GetValue(obj1), ma.GetValue(obj2)))) return false; return true; } public static int GetHashCode(object obj) { if (obj == null) throw new ArgumentNullException("obj"); int hash = 0; object value; foreach (MemberAccessor ma in GetAccessor(obj.GetType())) { value = ma.GetValue(obj); hash = ((hash << 5) + hash) ^ (value == null ? 0 : value.GetHashCode()); } return hash; } #endregion #region Abstract Members public abstract Type Type { get; } public abstract Type OriginalType { get; } #endregion #region Items private readonly ArrayList _members = new ArrayList(); private readonly Hashtable _memberNames = new Hashtable(); public MemberAccessor this[string memberName] { get { return (MemberAccessor)_memberNames[memberName]; } } public MemberAccessor this[int index] { get { return (MemberAccessor)_members[index]; } } public MemberAccessor this[NameOrIndexParameter nameOrIndex] { get { return (MemberAccessor) (nameOrIndex.ByName ? _memberNames[nameOrIndex.Name] : _members[nameOrIndex.Index]); } } #endregion #region Static Members [Obsolete("Use TypeFactory.LoadTypes instead")] public static bool LoadTypes { get { return TypeFactory.LoadTypes; } set { TypeFactory.LoadTypes = value; } } private static readonly Hashtable _accessors = new Hashtable(10); public static TypeAccessor GetAccessor(Type originalType) { if (originalType == null) throw new ArgumentNullException("originalType"); TypeAccessor accessor = (TypeAccessor)_accessors[originalType]; if (accessor == null) { lock (_accessors.SyncRoot) { accessor = (TypeAccessor)_accessors[originalType]; if (accessor == null) { if (IsAssociatedType(originalType)) return (TypeAccessor)_accessors[originalType]; Type instanceType = IsClassBulderNeeded(originalType)? null: originalType; if (instanceType == null) instanceType = TypeFactory.GetType(originalType); Type accessorType = TypeFactory.GetType(originalType, originalType, new TypeAccessorBuilder(instanceType, originalType)); accessor = (TypeAccessor)Activator.CreateInstance(accessorType); _accessors[originalType] = accessor; if (originalType != instanceType) _accessors[instanceType] = accessor; } } } return accessor; } public static TypeAccessor GetAccessor([NotNull] object obj) { if (obj == null) throw new ArgumentNullException("obj"); return GetAccessor(obj.GetType()); } public static TypeAccessor GetAccessor() { return TypeAccessor.Instance; } private static bool IsClassBulderNeeded(Type type) { if (type.IsAbstract && !type.IsSealed) { if (!type.IsInterface) { if (TypeHelper.GetDefaultConstructor(type) != null) return true; if (TypeHelper.GetConstructor(type, typeof(InitContext)) != null) return true; } else { object[] attrs = TypeHelper.GetAttributes(type, typeof(AutoImplementInterfaceAttribute)); if (attrs != null && attrs.Length > 0) return true; } } return false; } internal static bool IsInstanceBuildable(Type type) { if (!type.IsInterface) return true; lock (_accessors.SyncRoot) { if (_accessors[type] != null) return true; if (IsAssociatedType(type)) return true; } object[] attrs = TypeHelper.GetAttributes(type, typeof(AutoImplementInterfaceAttribute)); return attrs != null && attrs.Length > 0; } private static bool IsAssociatedType(Type type) { if (AssociatedTypeHandler != null) { Type child = AssociatedTypeHandler(type); if (child != null) { AssociateType(type, child); return true; } } return false; } public static object CreateInstance(Type type) { return GetAccessor(type).CreateInstance(); } public static object CreateInstance(Type type, InitContext context) { return GetAccessor(type).CreateInstance(context); } public static object CreateInstanceEx(Type type) { return GetAccessor(type).CreateInstanceEx(); } public static object CreateInstanceEx(Type type, InitContext context) { return GetAccessor(type).CreateInstance(context); } public static T CreateInstance() { return TypeAccessor.CreateInstance(); } public static T CreateInstance(InitContext context) { return TypeAccessor.CreateInstance(context); } public static T CreateInstanceEx() { return TypeAccessor.CreateInstanceEx(); } public static T CreateInstanceEx(InitContext context) { return TypeAccessor.CreateInstance(context); } public static TypeAccessor AssociateType(Type parent, Type child) { if (!TypeHelper.IsSameOrParent(parent, child)) throw new ArgumentException( string.Format("'{0}' must be a base type of '{1}'", parent, child), "child"); TypeAccessor accessor = GetAccessor(child); accessor = (TypeAccessor)Activator.CreateInstance(accessor.GetType()); lock (_accessors.SyncRoot) _accessors[parent] = accessor; return accessor; } public delegate Type GetAssociatedType(Type parent); public static event GetAssociatedType AssociatedTypeHandler; #endregion #region GetNullValue private static NullValueProvider _getNullValue = GetNullInternal; public static NullValueProvider GetNullValue { get { return _getNullValue ?? (_getNullValue = GetNullInternal);} set { _getNullValue = value; } } private static object GetNullInternal(Type type) { if (type == null) throw new ArgumentNullException("type"); if (type.IsValueType) { if (type.IsEnum) return GetEnumNullValue(type); if (type.IsPrimitive) { if (type == typeof(Int32)) return Common.Configuration.NullableValues.Int32; if (type == typeof(Double)) return Common.Configuration.NullableValues.Double; if (type == typeof(Int16)) return Common.Configuration.NullableValues.Int16; if (type == typeof(Boolean)) return Common.Configuration.NullableValues.Boolean; if (type == typeof(SByte)) return Common.Configuration.NullableValues.SByte; if (type == typeof(Int64)) return Common.Configuration.NullableValues.Int64; if (type == typeof(Byte)) return Common.Configuration.NullableValues.Byte; if (type == typeof(UInt16)) return Common.Configuration.NullableValues.UInt16; if (type == typeof(UInt32)) return Common.Configuration.NullableValues.UInt32; if (type == typeof(UInt64)) return Common.Configuration.NullableValues.UInt64; if (type == typeof(Single)) return Common.Configuration.NullableValues.Single; if (type == typeof(Char)) return Common.Configuration.NullableValues.Char; } else { if (type == typeof(DateTime)) return Common.Configuration.NullableValues.DateTime; #if FW3 if (type == typeof(DateTimeOffset)) return Common.Configuration.NullableValues.DateTimeOffset; #endif if (type == typeof(Decimal)) return Common.Configuration.NullableValues.Decimal; if (type == typeof(Guid)) return Common.Configuration.NullableValues.Guid; if (type == typeof(SqlInt32)) return SqlInt32. Null; if (type == typeof(SqlString)) return SqlString. Null; if (type == typeof(SqlBoolean)) return SqlBoolean. Null; if (type == typeof(SqlByte)) return SqlByte. Null; if (type == typeof(SqlDateTime)) return SqlDateTime.Null; if (type == typeof(SqlDecimal)) return SqlDecimal. Null; if (type == typeof(SqlDouble)) return SqlDouble. Null; if (type == typeof(SqlGuid)) return SqlGuid. Null; if (type == typeof(SqlInt16)) return SqlInt16. Null; if (type == typeof(SqlInt64)) return SqlInt64. Null; if (type == typeof(SqlMoney)) return SqlMoney. Null; if (type == typeof(SqlSingle)) return SqlSingle. Null; if (type == typeof(SqlBinary)) return SqlBinary. Null; } } else { if (type == typeof(String)) return Common.Configuration.NullableValues.String; if (type == typeof(DBNull)) return DBNull.Value; if (type == typeof(Stream)) return Stream.Null; if (type == typeof(SqlXml)) return SqlXml.Null; } return null; } const FieldAttributes EnumField = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal; private static readonly Hashtable _nullValues = new Hashtable(); private static object GetEnumNullValue(Type type) { object nullValue = _nullValues[type]; if (nullValue != null || _nullValues.Contains(type)) return nullValue; FieldInfo[] fields = type.GetFields(); foreach (FieldInfo fi in fields) { if ((fi.Attributes & EnumField) == EnumField) { Attribute[] attrs = Attribute.GetCustomAttributes(fi, typeof(NullValueAttribute)); if (attrs.Length > 0) { nullValue = Enum.Parse(type, fi.Name); break; } } } _nullValues[type] = nullValue; return nullValue; } private static IsNullHandler _isNull = IsNullInternal; public static IsNullHandler IsNull { get { return _isNull ?? (_isNull = IsNullInternal); } set { _isNull = value; } } private static bool IsNullInternal(object value) { if (value == null) return true; object nullValue = GetNullValue(value.GetType()); return nullValue != null && value.Equals(nullValue); } #endregion #region ICollection Members public void CopyTo(Array array, int index) { _members.CopyTo(array, index); } public int Count { get { return _members.Count; } } public bool IsSynchronized { get { return _members.IsSynchronized; } } public object SyncRoot { get { return _members.SyncRoot; } } public int IndexOf(MemberAccessor ma) { return _members.IndexOf(ma); } #endregion #region IEnumerable Members public IEnumerator GetEnumerator() { return _members.GetEnumerator(); } #endregion #region Write Object Info public static void WriteDebug(object o) { #if DEBUG Write(o, DebugWriteLine); #endif } private static void DebugWriteLine(string text) { Debug.WriteLine(text); } public static void WriteConsole(object o) { Write(o, Console.WriteLine); } [SuppressMessage("Microsoft.Performance", "CA1818:DoNotConcatenateStringsInsideLoops")] private static string MapTypeName(Type type) { if (type.IsGenericType) { if (type.GetGenericTypeDefinition() == typeof(Nullable<>)) return string.Format("{0}?", MapTypeName(Nullable.GetUnderlyingType(type))); string name = type.Name; int idx = name.IndexOf('`'); if (idx >= 0) name = name.Substring(0, idx); name += "<"; foreach (Type t in type.GetGenericArguments()) name += MapTypeName(t) + ','; if (name[name.Length - 1] == ',') name = name.Substring(0, name.Length - 1); name += ">"; return name; } if (type.IsPrimitive || type == typeof(string) || type == typeof(object) || type == typeof(decimal)) { if (type == typeof(int)) return "int"; if (type == typeof(bool)) return "bool"; if (type == typeof(short)) return "short"; if (type == typeof(long)) return "long"; if (type == typeof(ushort)) return "ushort"; if (type == typeof(uint)) return "uint"; if (type == typeof(ulong)) return "ulong"; if (type == typeof(float)) return "float"; return type.Name.ToLower(); } return type.Name; } public delegate void WriteLine(string text); [SuppressMessage("Microsoft.Usage", "CA2241:ProvideCorrectArgumentsToFormattingMethods")] public static void Write(object o, WriteLine writeLine) { if (o == null) { writeLine("*** (null) ***"); return; } TypeAccessor ta = GetAccessor(o.GetType()); MemberAccessor ma; int nameLen = 0; int typeLen = 0; foreach (DictionaryEntry de in ta._memberNames) { if (nameLen < de.Key.ToString().Length) nameLen = de.Key.ToString().Length; ma = (MemberAccessor)de.Value; if (typeLen < MapTypeName(ma.Type).Length) typeLen = MapTypeName(ma.Type).Length; } string text = "*** " + o.GetType().FullName + ": ***"; writeLine(text); string format = string.Format("{{0,-{0}}} {{1,-{1}}} : {{2}}", typeLen, nameLen); foreach (DictionaryEntry de in ta._memberNames) { ma = (MemberAccessor)de.Value; object value = ma.GetValue(o); if (value == null) value = "(null)"; else if (value is ICollection) value = string.Format("(Count = {0})", ((ICollection)value).Count); text = string.Format(format, MapTypeName(ma.Type), de.Key, value); writeLine(text); } writeLine("***"); } #endregion #region CustomTypeDescriptor private static readonly Hashtable _descriptors = new Hashtable(); public static ICustomTypeDescriptor GetCustomTypeDescriptor(Type type) { ICustomTypeDescriptor descriptor = (ICustomTypeDescriptor)_descriptors[type]; if (descriptor == null) { lock (_descriptors.SyncRoot) { descriptor = (ICustomTypeDescriptor)_descriptors[type]; if (descriptor == null) { descriptor = new CustomTypeDescriptorImpl(type); _descriptors.Add(type, descriptor); } } } return descriptor; } private ICustomTypeDescriptor _customTypeDescriptor; public ICustomTypeDescriptor CustomTypeDescriptor { get { if (_customTypeDescriptor == null) _customTypeDescriptor = GetCustomTypeDescriptor(OriginalType); return _customTypeDescriptor; } } #endregion #region Property Descriptors private PropertyDescriptorCollection _propertyDescriptors; public PropertyDescriptorCollection PropertyDescriptors { get { if (_propertyDescriptors == null) { if (TypeHelper.IsSameOrParent(typeof(ICustomTypeDescriptor), OriginalType)) { ICustomTypeDescriptor descriptor = CreateInstance() as ICustomTypeDescriptor; if (descriptor != null) _propertyDescriptors = descriptor.GetProperties(); } if (_propertyDescriptors == null) _propertyDescriptors = CreatePropertyDescriptors(); } return _propertyDescriptors; } } public PropertyDescriptorCollection CreatePropertyDescriptors() { Debug.WriteLineIf(BLToolkit.Data.DbManager.TraceSwitch.TraceInfo, OriginalType.FullName, "CreatePropertyDescriptors"); PropertyDescriptor[] pd = new PropertyDescriptor[Count]; int i = 0; foreach (MemberAccessor ma in _members) pd[i++] = ma.PropertyDescriptor; return new PropertyDescriptorCollection(pd); } public PropertyDescriptorCollection CreateExtendedPropertyDescriptors( Type objectViewType, IsNullHandler isNull) { // This is definitely wrong. // //if (isNull == null) // isNull = _isNull; PropertyDescriptorCollection pdc; pdc = CreatePropertyDescriptors(); if (objectViewType != null) { TypeAccessor viewAccessor = GetAccessor(objectViewType); IObjectView objectView = (IObjectView)viewAccessor.CreateInstanceEx(); List list = new List(); PropertyDescriptorCollection viewpdc = viewAccessor.PropertyDescriptors; foreach (PropertyDescriptor pd in viewpdc) list.Add(new ObjectViewPropertyDescriptor(pd, objectView)); foreach (PropertyDescriptor pd in pdc) if (viewpdc.Find(pd.Name, false) == null) list.Add(pd); pdc = new PropertyDescriptorCollection(list.ToArray()); } pdc = pdc.Sort(new PropertyDescriptorComparer()); pdc = GetExtendedProperties(pdc, OriginalType, String.Empty, Type.EmptyTypes, new PropertyDescriptor[0], isNull); return pdc; } private static PropertyDescriptorCollection GetExtendedProperties( PropertyDescriptorCollection pdc, Type itemType, string propertyPrefix, Type[] parentTypes, PropertyDescriptor[] parentAccessors, IsNullHandler isNull) { ArrayList list = new ArrayList(pdc.Count); ArrayList objects = new ArrayList(); bool isDataRow = itemType.IsSubclassOf(typeof(DataRow)); foreach (PropertyDescriptor p in pdc) { Type propertyType = p.PropertyType; if (p.Attributes.Matches(BindableAttribute.No) || //propertyType == typeof(Type) || isDataRow && p.Name == "ItemArray") continue; bool isList = false; bool explicitlyBound = p.Attributes.Contains(BindableAttribute.Yes); PropertyDescriptor pd = p; if (propertyType.GetInterface("IList") != null) { //if (!explicitlyBound) // continue; isList = true; pd = new ListPropertyDescriptor(pd); } if (!isList && !propertyType.IsValueType && !propertyType.IsArray && (!propertyType.FullName.StartsWith("System.") || explicitlyBound || propertyType.IsGenericType) && propertyType != typeof(Type) && propertyType != typeof(string) && propertyType != typeof(object) && Array.IndexOf(parentTypes, propertyType) == -1) { Type[] childParentTypes = new Type[parentTypes.Length + 1]; parentTypes.CopyTo(childParentTypes, 0); childParentTypes[parentTypes.Length] = itemType; PropertyDescriptor[] childParentAccessors = new PropertyDescriptor[parentAccessors.Length + 1]; parentAccessors.CopyTo(childParentAccessors, 0); childParentAccessors[parentAccessors.Length] = pd; PropertyDescriptorCollection pdch = GetAccessor(propertyType).PropertyDescriptors; pdch = pdch.Sort(new PropertyDescriptorComparer()); pdch = GetExtendedProperties( pdch, propertyType, propertyPrefix + pd.Name + "+", childParentTypes, childParentAccessors, isNull); objects.AddRange(pdch); } else { if (propertyPrefix.Length != 0 || isNull != null) pd = new StandardPropertyDescriptor(pd, propertyPrefix, parentAccessors, isNull); list.Add(pd); } } list.AddRange(objects); return new PropertyDescriptorCollection( (PropertyDescriptor[])list.ToArray(typeof(PropertyDescriptor))); } #region PropertyDescriptorComparer class PropertyDescriptorComparer : IComparer { public int Compare(object x, object y) { return String.Compare(((PropertyDescriptor)x).Name, ((PropertyDescriptor)y).Name); } } #endregion #region ListPropertyDescriptor class ListPropertyDescriptor : PropertyDescriptorWrapper { public ListPropertyDescriptor(PropertyDescriptor descriptor) : base(descriptor) { } public override object GetValue(object component) { object value = base.GetValue(component); if (value == null) return value; if (value is IBindingList && value is ITypedList) return value; return EditableArrayList.Adapter((IList)value); } } #endregion #region StandardPropertyDescriptor class StandardPropertyDescriptor : PropertyDescriptorWrapper { protected readonly PropertyDescriptor _descriptor = null; protected readonly IsNullHandler _isNull; protected readonly string _prefixedName; protected readonly PropertyDescriptor[] _chainAccessors; public StandardPropertyDescriptor( PropertyDescriptor pd, string namePrefix, PropertyDescriptor[] chainAccessors, IsNullHandler isNull) : base(pd) { _descriptor = pd; _isNull = isNull; _prefixedName = namePrefix + pd.Name; _chainAccessors = chainAccessors; } protected object GetNestedComponent(object component) { for (int i = 0; i < _chainAccessors.Length && component != null && !(component is DBNull); i++) { component = _chainAccessors[i].GetValue(component); } return component; } public override void SetValue(object component, object value) { component = GetNestedComponent(component); if (component != null && !(component is DBNull)) _descriptor.SetValue(component, value); } public override object GetValue(object component) { component = GetNestedComponent(component); return CheckNull( component != null && !(component is DBNull)? _descriptor.GetValue(component): null); } public override string Name { get { return _prefixedName; } } protected object CheckNull(object value) { if (_isNull != null && _isNull(value)) { switch (Common.Configuration.CheckNullReturnIfNull) { case Common.Configuration.NullEquivalent.DBNull: return DBNull.Value; case Common.Configuration.NullEquivalent.Null: return null; case Common.Configuration.NullEquivalent.Value: return value; } return DBNull.Value; } return value; } } #endregion #region objectViewPropertyDescriptor class ObjectViewPropertyDescriptor : PropertyDescriptorWrapper { public ObjectViewPropertyDescriptor(PropertyDescriptor pd, IObjectView objectView) : base(pd) { _objectView = objectView; } private readonly IObjectView _objectView; public override object GetValue(object component) { _objectView.Object = component; return base.GetValue(_objectView); } public override void SetValue(object component, object value) { _objectView.Object = component; base.SetValue(_objectView, value); } } #endregion #endregion #region ITypeDescriptionProvider Members string ITypeDescriptionProvider.ClassName { get { return OriginalType.Name; } } string ITypeDescriptionProvider.ComponentName { get { return OriginalType.Name; } } EventDescriptor ITypeDescriptionProvider.GetEvent(string name) { return new CustomEventDescriptor(OriginalType.GetEvent(name)); } PropertyDescriptor ITypeDescriptionProvider.GetProperty(string name) { MemberAccessor ma = this[name]; return ma != null ? ma.PropertyDescriptor : null; } AttributeCollection ITypeDescriptionProvider.GetAttributes() { return new AttributeCollection((Attribute[])new TypeHelper(OriginalType).GetAttributes()); } EventDescriptorCollection ITypeDescriptionProvider.GetEvents() { EventInfo[] ei = OriginalType.GetEvents(); EventDescriptor[] ed = new EventDescriptor[ei.Length]; for (int i = 0; i < ei.Length; i++) ed[i] = new CustomEventDescriptor(ei[i]); return new EventDescriptorCollection(ed); } PropertyDescriptorCollection ITypeDescriptionProvider.GetProperties() { return CreatePropertyDescriptors(); } #region CustomEventDescriptor class CustomEventDescriptor : EventDescriptor { public CustomEventDescriptor(EventInfo eventInfo) : base(eventInfo.Name, null) { _eventInfo = eventInfo; } private readonly EventInfo _eventInfo; public override void AddEventHandler(object component, Delegate value) { _eventInfo.AddEventHandler(component, value); } public override void RemoveEventHandler(object component, Delegate value) { _eventInfo.RemoveEventHandler(component, value); } public override Type ComponentType { get { return _eventInfo.DeclaringType; } } public override Type EventType { get { return _eventInfo.EventHandlerType; } } public override bool IsMulticast { get { return _eventInfo.IsMulticast; } } } #endregion #endregion } }