1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Reflection; 5 using System.Collections; 6 using System.Security; 7 using System.Security.Permissions; 8 using System.Linq; 9 10 namespace System.Data.Linq.SqlClient { 11 internal static class TypeSystem { 12 IsSequenceType(Type seqType)13 internal static bool IsSequenceType(Type seqType) { 14 return seqType != typeof(string) 15 && seqType != typeof(byte[]) 16 && seqType != typeof(char[]) 17 && FindIEnumerable(seqType) != null; 18 } HasIEnumerable(Type seqType)19 internal static bool HasIEnumerable(Type seqType) { 20 return FindIEnumerable(seqType) != null; 21 } FindIEnumerable(Type seqType)22 private static Type FindIEnumerable(Type seqType) { 23 if (seqType == null || seqType == typeof(string)) 24 return null; 25 if (seqType.IsArray) 26 return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType()); 27 if (seqType.IsGenericType) { 28 foreach (Type arg in seqType.GetGenericArguments()) { 29 Type ienum = typeof(IEnumerable<>).MakeGenericType(arg); 30 if (ienum.IsAssignableFrom(seqType)) { 31 return ienum; 32 } 33 } 34 } 35 Type[] ifaces = seqType.GetInterfaces(); 36 if (ifaces != null && ifaces.Length > 0) { 37 foreach (Type iface in ifaces) { 38 Type ienum = FindIEnumerable(iface); 39 if (ienum != null) return ienum; 40 } 41 } 42 if (seqType.BaseType != null && seqType.BaseType != typeof(object)) { 43 return FindIEnumerable(seqType.BaseType); 44 } 45 return null; 46 } GetFlatSequenceType(Type elementType)47 internal static Type GetFlatSequenceType(Type elementType) { 48 Type ienum = FindIEnumerable(elementType); 49 if (ienum != null) return ienum; 50 return typeof(IEnumerable<>).MakeGenericType(elementType); 51 } GetSequenceType(Type elementType)52 internal static Type GetSequenceType(Type elementType) { 53 return typeof(IEnumerable<>).MakeGenericType(elementType); 54 } GetElementType(Type seqType)55 internal static Type GetElementType(Type seqType) { 56 Type ienum = FindIEnumerable(seqType); 57 if (ienum == null) return seqType; 58 return ienum.GetGenericArguments()[0]; 59 } IsNullableType(Type type)60 internal static bool IsNullableType(Type type) { 61 return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); 62 } IsNullAssignable(Type type)63 internal static bool IsNullAssignable(Type type) { 64 return !type.IsValueType || IsNullableType(type); 65 } GetNonNullableType(Type type)66 internal static Type GetNonNullableType(Type type) { 67 if (IsNullableType(type)) { 68 return type.GetGenericArguments()[0]; 69 } 70 return type; 71 } GetMemberType(MemberInfo mi)72 internal static Type GetMemberType(MemberInfo mi) { 73 FieldInfo fi = mi as FieldInfo; 74 if (fi != null) return fi.FieldType; 75 PropertyInfo pi = mi as PropertyInfo; 76 if (pi != null) return pi.PropertyType; 77 EventInfo ei = mi as EventInfo; 78 if (ei != null) return ei.EventHandlerType; 79 return null; 80 } GetAllFields(Type type, BindingFlags flags)81 internal static IEnumerable<FieldInfo> GetAllFields(Type type, BindingFlags flags) { 82 Dictionary<MetaPosition, FieldInfo> seen = new Dictionary<MetaPosition, FieldInfo>(); 83 Type currentType = type; 84 do { 85 foreach (FieldInfo fi in currentType.GetFields(flags)) { 86 if (fi.IsPrivate || type == currentType) { 87 MetaPosition mp = new MetaPosition(fi); 88 seen[mp] = fi; 89 } 90 } 91 currentType = currentType.BaseType; 92 } while (currentType != null); 93 return seen.Values; 94 } GetAllProperties(Type type, BindingFlags flags)95 internal static IEnumerable<PropertyInfo> GetAllProperties(Type type, BindingFlags flags) { 96 Dictionary<MetaPosition, PropertyInfo> seen = new Dictionary<MetaPosition, PropertyInfo>(); 97 Type currentType = type; 98 do { 99 foreach (PropertyInfo pi in currentType.GetProperties(flags)) { 100 if (type == currentType || IsPrivate(pi)) { 101 MetaPosition mp = new MetaPosition(pi); 102 seen[mp] = pi; 103 } 104 } 105 currentType = currentType.BaseType; 106 } while (currentType != null); 107 return seen.Values; 108 } 109 IsPrivate(PropertyInfo pi)110 private static bool IsPrivate(PropertyInfo pi) { 111 MethodInfo mi = pi.GetGetMethod() ?? pi.GetSetMethod(); 112 if (mi != null) { 113 return mi.IsPrivate; 114 } 115 return true; 116 } 117 118 private static ILookup<string, MethodInfo> _sequenceMethods; FindSequenceMethod(string name, Type[] args, params Type[] typeArgs)119 internal static MethodInfo FindSequenceMethod(string name, Type[] args, params Type[] typeArgs) { 120 if (_sequenceMethods == null) { 121 _sequenceMethods = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).ToLookup(m => m.Name); 122 } 123 MethodInfo mi = _sequenceMethods[name].FirstOrDefault(m => ArgsMatchExact(m, args, typeArgs)); 124 if (mi == null) 125 return null; 126 if (typeArgs != null) 127 return mi.MakeGenericMethod(typeArgs); 128 return mi; 129 } FindSequenceMethod(string name, IEnumerable sequence)130 internal static MethodInfo FindSequenceMethod(string name, IEnumerable sequence) { 131 return FindSequenceMethod(name, new Type[] {sequence.GetType()}, new Type[] {GetElementType(sequence.GetType())}); 132 } 133 134 private static ILookup<string, MethodInfo> _queryMethods; FindQueryableMethod(string name, Type[] args, params Type[] typeArgs)135 internal static MethodInfo FindQueryableMethod(string name, Type[] args, params Type[] typeArgs) { 136 if (_queryMethods == null) { 137 _queryMethods = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public).ToLookup(m => m.Name); 138 } 139 MethodInfo mi = _queryMethods[name].FirstOrDefault(m => ArgsMatchExact(m, args, typeArgs)); 140 if (mi == null) 141 throw Error.NoMethodInTypeMatchingArguments(typeof(Queryable)); 142 if (typeArgs != null) 143 return mi.MakeGenericMethod(typeArgs); 144 return mi; 145 } 146 FindStaticMethod(Type type, string name, Type[] args, params Type[] typeArgs)147 internal static MethodInfo FindStaticMethod(Type type, string name, Type[] args, params Type[] typeArgs) { 148 MethodInfo mi = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) 149 .FirstOrDefault(m => m.Name == name && ArgsMatchExact(m, args, typeArgs)); 150 if (mi == null) 151 throw Error.NoMethodInTypeMatchingArguments(type); 152 if (typeArgs != null) 153 return mi.MakeGenericMethod(typeArgs); 154 return mi; 155 } 156 ArgsMatchExact(MethodInfo m, Type[] argTypes, Type[] typeArgs)157 private static bool ArgsMatchExact(MethodInfo m, Type[] argTypes, Type[] typeArgs) { 158 ParameterInfo[] mParams = m.GetParameters(); 159 if (mParams.Length != argTypes.Length) 160 return false; 161 if (!m.IsGenericMethodDefinition && m.IsGenericMethod && m.ContainsGenericParameters) { 162 m = m.GetGenericMethodDefinition(); 163 } 164 if (m.IsGenericMethodDefinition) { 165 if (typeArgs == null || typeArgs.Length == 0) 166 return false; 167 if (m.GetGenericArguments().Length != typeArgs.Length) 168 return false; 169 m = m.MakeGenericMethod(typeArgs); 170 mParams = m.GetParameters(); 171 } 172 else if (typeArgs != null && typeArgs.Length > 0) { 173 return false; 174 } 175 for (int i = 0, n = argTypes.Length; i < n; i++) { 176 Type parameterType = mParams[i].ParameterType; 177 if (parameterType == null) 178 return false; 179 Type argType = argTypes[i]; 180 if (!parameterType.IsAssignableFrom(argType)) 181 return false; 182 } 183 return true; 184 } 185 186 /// <summary> 187 /// Returns true if the type is one of the built in simple types. 188 /// </summary> IsSimpleType(Type type)189 internal static bool IsSimpleType(Type type) 190 { 191 if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) 192 type = type.GetGenericArguments()[0]; 193 194 if (type.IsEnum) 195 return true; 196 197 if (type == typeof(Guid)) 198 return true; 199 200 TypeCode tc = Type.GetTypeCode(type); 201 switch (tc) 202 { 203 case TypeCode.Byte: 204 case TypeCode.SByte: 205 case TypeCode.Int16: 206 case TypeCode.Int32: 207 case TypeCode.Int64: 208 case TypeCode.UInt16: 209 case TypeCode.UInt32: 210 case TypeCode.UInt64: 211 case TypeCode.Single: 212 case TypeCode.Double: 213 case TypeCode.Decimal: 214 case TypeCode.Char: 215 case TypeCode.String: 216 case TypeCode.Boolean: 217 case TypeCode.DateTime: 218 return true; 219 case TypeCode.Object: 220 return (typeof(TimeSpan) == type) || (typeof(DateTimeOffset) == type); 221 default: 222 return false; 223 } 224 } 225 } 226 227 /// <summary> 228 /// Hashable MetaDataToken+Assembly. This type uniquely describes a metadata element 229 /// like a MemberInfo. MetaDataToken by itself is not sufficient because its only 230 /// unique within a single assembly. 231 /// </summary> 232 internal struct MetaPosition : IEqualityComparer<MetaPosition>, IEqualityComparer { 233 private int metadataToken; 234 private Assembly assembly; MetaPositionSystem.Data.Linq.SqlClient.MetaPosition235 internal MetaPosition(MemberInfo mi) 236 : this(mi.DeclaringType.Assembly, mi.MetadataToken) { 237 } MetaPositionSystem.Data.Linq.SqlClient.MetaPosition238 private MetaPosition(Assembly assembly, int metadataToken) { 239 this.assembly = assembly; 240 this.metadataToken = metadataToken; 241 } 242 243 // Equality is implemented here according to the advice in 244 // CLR via C# 2ed, J. Richter, p 146. In particular, ValueType.Equals 245 // should not be called for perf reasons. 246 247 #region Object Members EqualsSystem.Data.Linq.SqlClient.MetaPosition248 public override bool Equals(object obj) { 249 if (obj == null) 250 return false; 251 252 if (obj.GetType() != this.GetType()) 253 return false; 254 255 return AreEqual(this, (MetaPosition)obj); 256 } GetHashCodeSystem.Data.Linq.SqlClient.MetaPosition257 public override int GetHashCode() { 258 return metadataToken; 259 } 260 #endregion 261 262 #region IEqualityComparer<MetaPosition> Members EqualsSystem.Data.Linq.SqlClient.MetaPosition263 public bool Equals(MetaPosition x, MetaPosition y) { 264 return AreEqual(x, y); 265 } 266 GetHashCodeSystem.Data.Linq.SqlClient.MetaPosition267 public int GetHashCode(MetaPosition obj) { 268 return obj.metadataToken; 269 } 270 #endregion 271 272 #region IEqualityComparer Members IEqualityComparer.EqualsSystem.Data.Linq.SqlClient.MetaPosition273 bool IEqualityComparer.Equals(object x, object y) { 274 return this.Equals((MetaPosition)x, (MetaPosition)y); 275 } IEqualityComparer.GetHashCodeSystem.Data.Linq.SqlClient.MetaPosition276 int IEqualityComparer.GetHashCode(object obj) { 277 return this.GetHashCode((MetaPosition) obj); 278 } 279 #endregion 280 AreEqualSystem.Data.Linq.SqlClient.MetaPosition281 private static bool AreEqual(MetaPosition x, MetaPosition y) { 282 return (x.metadataToken == y.metadataToken) 283 && (x.assembly == y.assembly); 284 } 285 286 // Since MetaPositions are immutable, we overload the equality operator 287 // to test for value equality, rather than reference equality operator ==System.Data.Linq.SqlClient.MetaPosition288 public static bool operator==(MetaPosition x, MetaPosition y) { 289 return AreEqual(x, y); 290 } operator !=System.Data.Linq.SqlClient.MetaPosition291 public static bool operator !=(MetaPosition x, MetaPosition y) { 292 return !AreEqual(x, y); 293 } 294 AreSameMemberSystem.Data.Linq.SqlClient.MetaPosition295 internal static bool AreSameMember(MemberInfo x, MemberInfo y) { 296 if (x.MetadataToken != y.MetadataToken || x.DeclaringType.Assembly != y.DeclaringType.Assembly) { 297 return false; 298 } 299 return true; 300 } 301 } 302 } 303