<PackageReference Include="Castle.Core" Version="5.0.0" />

CustomAttributeInfo

Encapsulates the information needed to build an attribute.
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; namespace Castle.DynamicProxy { public class CustomAttributeInfo : IEquatable<CustomAttributeInfo> { private class AttributeArgumentValueEqualityComparer : IEqualityComparer<object> { bool IEqualityComparer<object>.Equals(object x, object y) { if (x == y) return true; if (x == null || y == null) return false; if (x.GetType() != y.GetType()) return false; if (x.GetType().IsArray) return AsObjectEnumerable(x).SequenceEqual(AsObjectEnumerable(y)); return x.Equals(y); } int IEqualityComparer<object>.GetHashCode(object obj) { if (obj == null) return 0; if (obj.GetType().IsArray) return CombineHashCodes(AsObjectEnumerable(obj)); return obj.GetHashCode(); } private static IEnumerable<object> AsObjectEnumerable(object array) { if (array.GetType().GetElementType().IsValueType) return ((Array)array).Cast<object>(); return (IEnumerable<object>)array; } } private static readonly PropertyInfo[] EmptyProperties = new PropertyInfo[0]; private static readonly FieldInfo[] EmptyFields = new FieldInfo[0]; private static readonly object[] EmptyValues = new object[0]; private static readonly IEqualityComparer<object> ValueComparer = new AttributeArgumentValueEqualityComparer(); private readonly CustomAttributeBuilder builder; private readonly ConstructorInfo constructor; private readonly object[] constructorArgs; private readonly IDictionary<string, object> properties; private readonly IDictionary<string, object> fields; internal CustomAttributeBuilder Builder => builder; public CustomAttributeInfo(ConstructorInfo constructor, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues) { builder = new CustomAttributeBuilder(constructor, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues); this.constructor = constructor; this.constructorArgs = ((constructorArgs.Length == 0) ? EmptyValues : constructorArgs.ToArray()); properties = MakeNameValueDictionary(namedProperties, propertyValues); fields = MakeNameValueDictionary(namedFields, fieldValues); } public CustomAttributeInfo(ConstructorInfo constructor, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues) : this(constructor, constructorArgs, namedProperties, propertyValues, EmptyFields, EmptyValues) { } public CustomAttributeInfo(ConstructorInfo constructor, object[] constructorArgs, FieldInfo[] namedFields, object[] fieldValues) : this(constructor, constructorArgs, EmptyProperties, EmptyValues, namedFields, fieldValues) { } public CustomAttributeInfo(ConstructorInfo constructor, object[] constructorArgs) : this(constructor, constructorArgs, EmptyProperties, EmptyValues, EmptyFields, EmptyValues) { } public static CustomAttributeInfo FromExpression(Expression<Func<Attribute>> expression) { List<PropertyInfo> list = new List<PropertyInfo>(); List<object> list2 = new List<object>(); List<FieldInfo> list3 = new List<FieldInfo>(); List<object> list4 = new List<object>(); Expression expression2 = UnwrapBody(expression.Body); NewExpression newExpression = expression2 as NewExpression; if (newExpression == null) { MemberInitExpression obj = expression2 as MemberInitExpression; if (obj == null) throw new ArgumentException("The expression must be either a simple constructor call or an object initializer expression"); newExpression = obj.NewExpression; foreach (MemberBinding binding in obj.Bindings) { MemberAssignment memberAssignment = binding as MemberAssignment; if (memberAssignment == null) throw new ArgumentException("Only assignment bindings are supported"); object attributeArgumentValue = GetAttributeArgumentValue(memberAssignment.Expression, true); PropertyInfo propertyInfo = memberAssignment.Member as PropertyInfo; if (propertyInfo != (PropertyInfo)null) { list.Add(propertyInfo); list2.Add(attributeArgumentValue); } else { FieldInfo fieldInfo = memberAssignment.Member as FieldInfo; if (!(fieldInfo != (FieldInfo)null)) throw new ArgumentException("Only property and field assignments are supported"); list3.Add(fieldInfo); list4.Add(attributeArgumentValue); } } } List<object> list5 = new List<object>(); foreach (Expression argument in newExpression.Arguments) { object attributeArgumentValue2 = GetAttributeArgumentValue(argument, true); list5.Add(attributeArgumentValue2); } return new CustomAttributeInfo(newExpression.Constructor, list5.ToArray(), list.ToArray(), list2.ToArray(), list3.ToArray(), list4.ToArray()); } private static Expression UnwrapBody(Expression body) { UnaryExpression unaryExpression = body as UnaryExpression; if (unaryExpression != null && unaryExpression.NodeType == ExpressionType.Convert) return unaryExpression.Operand; return body; } private static object GetAttributeArgumentValue(Expression arg, bool allowArray) { switch (arg.NodeType) { case ExpressionType.Constant: return ((ConstantExpression)arg).Value; case ExpressionType.MemberAccess: { MemberExpression memberExpression = (MemberExpression)arg; FieldInfo fieldInfo = memberExpression.Member as FieldInfo; if ((object)fieldInfo != null) { ConstantExpression constantExpression = memberExpression.Expression as ConstantExpression; if (constantExpression != null && IsCompilerGenerated(constantExpression.Type) && constantExpression.Value != null) return fieldInfo.GetValue(constantExpression.Value); } break; } case ExpressionType.NewArrayInit: if (allowArray) { NewArrayExpression newArrayExpression = (NewArrayExpression)arg; Array array = Array.CreateInstance(newArrayExpression.Type.GetElementType(), newArrayExpression.Expressions.Count); int num = 0; { foreach (Expression expression in newArrayExpression.Expressions) { object attributeArgumentValue = GetAttributeArgumentValue(expression, false); array.SetValue(attributeArgumentValue, num); num++; } return array; } } break; } throw new ArgumentException("Only constant, local variables, method parameters and single-dimensional array expressions are supported"); } private static bool IsCompilerGenerated(Type type) { return CustomAttributeExtensions.IsDefined(type, typeof(CompilerGeneratedAttribute)); } public bool Equals(CustomAttributeInfo other) { if (other == null) return false; if (this == other) return true; if (constructor.Equals(other.constructor) && constructorArgs.SequenceEqual(other.constructorArgs, ValueComparer) && AreMembersEquivalent(properties, other.properties)) return AreMembersEquivalent(fields, other.fields); return false; } public override bool Equals(object obj) { if (obj == null) return false; if (this == obj) return true; if (obj.GetType() != GetType()) return false; return Equals((CustomAttributeInfo)obj); } public override int GetHashCode() { return (((((constructor.GetHashCode() * 397) ^ CombineHashCodes(constructorArgs)) * 397) ^ CombineMemberHashCodes(properties)) * 397) ^ CombineMemberHashCodes(fields); } private static bool AreMembersEquivalent(IDictionary<string, object> x, IDictionary<string, object> y) { if (x.Count != y.Count) return false; foreach (KeyValuePair<string, object> item in x) { if (!y.TryGetValue(item.Key, out object value)) return false; if (!ValueComparer.Equals(item.Value, value)) return false; } return true; } private static int CombineHashCodes(IEnumerable<object> values) { int num = 173; foreach (object value in values) { num = ((num * 397) ^ ValueComparer.GetHashCode(value)); } return num; } private static int CombineMemberHashCodes(IDictionary<string, object> dict) { int num = 0; foreach (KeyValuePair<string, object> item in dict) { int hashCode = item.Key.GetHashCode(); int hashCode2 = ValueComparer.GetHashCode(item.Value); num += ((hashCode * 397) ^ hashCode2); } return num; } private IDictionary<string, object> MakeNameValueDictionary<T>(T[] members, object[] values) where T : MemberInfo { Dictionary<string, object> dictionary = new Dictionary<string, object>(); for (int i = 0; i < members.Length; i++) { dictionary.Add(members[i].Name, values[i]); } return dictionary; } } }