Welcome to mirror list, hosted at ThFree Co, Russian Federation.

TypeSystem.cs « ELinq « Objects « Data « System « System.Data.Entity « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 1d0e4a7f1a56063b867f60c9ab11599cd3c5f7cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
//---------------------------------------------------------------------
// <copyright file="TypeSystem.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// @owner  [....]
//---------------------------------------------------------------------

namespace System.Data.Objects.ELinq
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Runtime.CompilerServices;

    /// <summary>
    /// Static utility class. Replica of query\DLinq\TypeSystem.cs
    /// </summary>
    internal static class TypeSystem
    {
        private static readonly MethodInfo s_getDefaultMethod = typeof(TypeSystem).GetMethod(
            "GetDefault", BindingFlags.Static | BindingFlags.NonPublic);
        private static T GetDefault<T>() { return default(T); }

        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
        internal static object GetDefaultValue(Type type)
        {
            // null is always the default for non value types and Nullable<>
            if (!type.IsValueType ||
                (type.IsGenericType &&
                 typeof(Nullable<>) == type.GetGenericTypeDefinition()))
            {
                return null;
            }
            MethodInfo getDefaultMethod = s_getDefaultMethod.MakeGenericMethod(type);
            object defaultValue = getDefaultMethod.Invoke(null, new object[] { });
            return defaultValue;
        }

        internal static bool IsSequenceType(Type seqType)
        {
            return FindIEnumerable(seqType) != null;
        }

        internal static Type GetDelegateType(IEnumerable<Type> inputTypes, Type returnType)
        {
            EntityUtil.CheckArgumentNull(returnType, "returnType");

            // Determine Func<> type (generic args are the input parameter types plus the return type)
            inputTypes = inputTypes ?? Enumerable.Empty<Type>();
            int argCount = inputTypes.Count();
            Type[] typeArgs = new Type[argCount + 1];
            int i = 0;
            foreach (Type typeArg in inputTypes)
            {
                typeArgs[i++] = typeArg;
            }
            typeArgs[i] = returnType;

            // Find appropriate Func<>
            Type delegateType;
            switch (argCount)
            {
                case 0: delegateType = typeof(Func<>); break;
                case 1: delegateType = typeof(Func<,>); break;
                case 2: delegateType = typeof(Func<,,>); break;
                case 3: delegateType = typeof(Func<,,,>); break;
                case 4: delegateType = typeof(Func<,,,,>); break;
                case 5: delegateType = typeof(Func<,,,,,>); break;
                case 6: delegateType = typeof(Func<,,,,,,>); break;
                case 7: delegateType = typeof(Func<,,,,,,,>); break;
                case 8: delegateType = typeof(Func<,,,,,,,,>); break;
                case 9: delegateType = typeof(Func<,,,,,,,,,>); break;
                case 10: delegateType = typeof(Func<,,,,,,,,,,>); break;
                case 11: delegateType = typeof(Func<,,,,,,,,,,,>); break;
                case 12: delegateType = typeof(Func<,,,,,,,,,,,,>); break;
                case 13: delegateType = typeof(Func<,,,,,,,,,,,,,>); break;
                case 14: delegateType = typeof(Func<,,,,,,,,,,,,,,>); break;
                case 15: delegateType = typeof(Func<,,,,,,,,,,,,,,,>); break;
                default: Debug.Fail("unexpected argument count"); delegateType = null; break;
            }
            delegateType = delegateType.MakeGenericType(typeArgs);

            return delegateType;
        }

        internal static Expression EnsureType(Expression expression, Type requiredType)
        {
            Debug.Assert(null != expression, "expression required");
            Debug.Assert(null != requiredType, "requiredType");
            if (expression.Type != requiredType)
            {
                expression = Expression.Convert(expression, requiredType);
            }
            return expression;
        }

        /// <summary>
        /// Resolves MemberInfo to a property or field.
        /// </summary>
        /// <param name="member">Member to test.</param>
        /// <param name="name">Name of member.</param>
        /// <param name="type">Type of member.</param>
        /// <returns>Given member normalized as a property or field.</returns>
        internal static MemberInfo PropertyOrField(MemberInfo member, out string name, out Type type)
        {
            name = null;
            type = null;

            if (member.MemberType == MemberTypes.Field)
            {
                FieldInfo field = (FieldInfo)member;
                name = field.Name;
                type = field.FieldType;
                return field;
            }
            else if (member.MemberType == MemberTypes.Property)
            {
                PropertyInfo property = (PropertyInfo)member;
                if (0 != property.GetIndexParameters().Length)
                {
                    // don't support indexed properties
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_PropertyIndexNotSupported);
                }
                name = property.Name;
                type = property.PropertyType;
                return property;
            }
            else if (member.MemberType == MemberTypes.Method)
            {
                // this may be a property accessor in disguise (if it's a RuntimeMethodHandle)
                MethodInfo method = (MethodInfo)member;
                if (method.IsSpecialName) // property accessor methods must set IsSpecialName
                {
                    // try to find a property with the given getter
                    foreach (PropertyInfo property in method.DeclaringType.GetProperties(
                        BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
                    {
                        if (property.CanRead && (property.GetGetMethod(true) == method))
                        {
                            return PropertyOrField(property, out name, out type);
                        }
                    }
                }
            }
            throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_NotPropertyOrField(member.Name));
        }
                
        private static Type FindIEnumerable(Type seqType)
        {
            // Ignores "terminal" primitive types in the EDM although they may implement IEnumerable<>
            if (seqType == null || seqType == typeof(string) || seqType == typeof(byte[]))
                return null;
            if (seqType.IsArray)
                return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType());
            if (seqType.IsGenericType)
            {
                foreach (Type arg in seqType.GetGenericArguments())
                {
                    Type ienum = typeof(IEnumerable<>).MakeGenericType(arg);
                    if (ienum.IsAssignableFrom(seqType))
                    {
                        return ienum;
                    }
                }
            }
            Type[] ifaces = seqType.GetInterfaces();
            if (ifaces != null && ifaces.Length > 0)
            {
                foreach (Type iface in ifaces)
                {
                    Type ienum = FindIEnumerable(iface);
                    if (ienum != null) return ienum;
                }
            }
            if (seqType.BaseType != null && seqType.BaseType != typeof(object))
            {
                return FindIEnumerable(seqType.BaseType);
            }
            return null;
        }
        internal static Type GetElementType(Type seqType)
        {
            Type ienum = FindIEnumerable(seqType);
            if (ienum == null) return seqType;
            return ienum.GetGenericArguments()[0];
        }
        internal static bool IsNullableType(Type type)
        {
            var nonNullableType = GetNonNullableType(type);

            return nonNullableType != null && nonNullableType != type;
        }
        internal static Type GetNonNullableType(Type type)
        {
            if (type != null)
            {
                return Nullable.GetUnderlyingType(type) ?? type;
            }

            return null;
        }

        internal static bool IsImplementationOfGenericInterfaceMethod(this MethodInfo test, Type match, out Type[] genericTypeArguments)
        {
            genericTypeArguments = null;

            // check requirements for a match
            if (null == test || null == match || !match.IsInterface || !match.IsGenericTypeDefinition || null == test.DeclaringType)
            {
                return false;
            }

            // we might be looking at the interface implementation directly
            if (test.DeclaringType.IsInterface && test.DeclaringType.IsGenericType && test.DeclaringType.GetGenericTypeDefinition() == match)
            {
                return true;
            }

            // figure out if we implement the interface
            foreach (Type testInterface in test.DeclaringType.GetInterfaces())
            {
                if (testInterface.IsGenericType && testInterface.GetGenericTypeDefinition() == match)
                {
                    // check if the method aligns
                    var map = test.DeclaringType.GetInterfaceMap(testInterface);
                    if (map.TargetMethods.Contains(test))
                    {
                        genericTypeArguments = testInterface.GetGenericArguments();
                        return true;
                    }
                }
            }

            return false;
        }

        internal static bool IsImplementationOf(this PropertyInfo propertyInfo, Type interfaceType)
        {
            Debug.Assert(interfaceType.IsInterface, "Ensure interfaceType is an interface before calling IsImplementationOf");
            
            // Find the property with the corresponding name on the interface, if present
            PropertyInfo interfaceProp = interfaceType.GetProperty(propertyInfo.Name, BindingFlags.Public | BindingFlags.Instance);
            if (null == interfaceProp)
            {
                return false;
            }

            // If the declaring type is an interface, compare directly.
            if (propertyInfo.DeclaringType.IsInterface)
            {
                return interfaceProp.Equals(propertyInfo);
            }

            Debug.Assert(Enumerable.Contains(propertyInfo.DeclaringType.GetInterfaces(), interfaceType), "Ensure propertyInfo.DeclaringType implements interfaceType before calling IsImplementationOf");

            bool result = false;

            // Get the get_<Property> method from the interface property.
            MethodInfo getInterfaceProp = interfaceProp.GetGetMethod();

            // Retrieve the interface mapping for the interface on the candidate property's declaring type.
            InterfaceMapping interfaceMap = propertyInfo.DeclaringType.GetInterfaceMap(interfaceType);
                        
            // Find the index of the interface's get_<Property> method in the interface methods of the interface map
            int propIndex = Array.IndexOf(interfaceMap.InterfaceMethods, getInterfaceProp);
            
            // Find the method on the property's declaring type that is the target of the interface's get_<Property> method.
            // This method will be at the same index in the interface mapping's target methods as the get_<Property> interface method index.
            MethodInfo[] targetMethods = interfaceMap.TargetMethods;
            if (propIndex > -1 && propIndex < targetMethods.Length)
            {
                // If the get method of the referenced property is the target of the get_<Property> method in this interface mapping,
                // then the property is the implementation of the interface's corresponding property.
                MethodInfo getPropertyMethod = propertyInfo.GetGetMethod();
                if (getPropertyMethod != null)
                {
                    result = getPropertyMethod.Equals(targetMethods[propIndex]);
                }
            }

            return result;
        }
    }
}