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