[corlib] Generic comparers from reference sources
[mono.git] / mcs / class / corlib / ReferenceSources / RuntimeType.cs
1 //
2 // RuntimeType.cs
3 //
4 // Authors:
5 //      Marek Safar  <marek.safar@gmail.com>
6 //
7 // Copyright (C) 2015 Xamarin Inc (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System.Reflection;
30 using System.Runtime.CompilerServices;
31 using System.Threading;
32 using System.Collections.Generic;
33 using System.Runtime.InteropServices;
34 using System.Globalization;
35 #if MONO_COM
36 using System.Reflection.Emit;
37 #endif
38 using System.Diagnostics.Contracts;
39 using System.Security;
40 using System.Runtime.Serialization;
41
42 namespace System
43 {
44         partial class RuntimeType
45         {
46                 internal virtual MonoCMethod GetDefaultConstructor ()
47                 {
48                         // TODO: Requires MonoType
49                         throw new NotSupportedException ();
50                 }
51
52                 string GetDefaultMemberName ()
53                 {
54                         object [] att = GetCustomAttributes (typeof (DefaultMemberAttribute), true);
55                         return att.Length != 0 ? ((DefaultMemberAttribute) att [0]).MemberName : null;
56                 }
57
58                 RuntimeConstructorInfo m_serializationCtor;
59                 internal RuntimeConstructorInfo GetSerializationCtor()
60                 {
61                         if (m_serializationCtor == null) {
62                                 var s_SICtorParamTypes = new Type[] { typeof(SerializationInfo), typeof(StreamingContext) };
63
64                                 m_serializationCtor = GetConstructor(
65                                         BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
66                                         null,
67                                         CallingConventions.Any,
68                                         s_SICtorParamTypes,
69                                         null) as RuntimeConstructorInfo;
70                         }
71
72                         return m_serializationCtor;
73                 }
74
75                 internal Object CreateInstanceSlow(bool publicOnly, bool skipCheckThis, bool fillCache, ref StackCrawlMark stackMark)
76                 {
77                         bool bNeedSecurityCheck = true;
78                         bool bCanBeCached = false;
79                         bool bSecurityCheckOff = false;
80
81                         if (!skipCheckThis)
82                                 CreateInstanceCheckThis();
83
84                         if (!fillCache)
85                                 bSecurityCheckOff = true;
86
87                         return CreateInstanceMono (!publicOnly);
88                 }
89
90                 object CreateInstanceMono (bool nonPublic)
91                 {
92                         var ctor = GetDefaultConstructor ();
93                         if (!nonPublic && ctor != null && !ctor.IsPublic) {
94                                 ctor = null;
95                         }
96
97                         if (ctor == null) {
98                                 Type elementType = this.GetRootElementType();
99                                 if (ReferenceEquals (elementType, typeof (TypedReference)) || ReferenceEquals (elementType, typeof (RuntimeArgumentHandle)))
100                                         throw new NotSupportedException (Environment.GetResourceString ("NotSupported_ContainsStackPtr"));
101
102                                 if (IsValueType)
103                                         return CreateInstanceInternal (this);
104
105                                 throw new MissingMethodException (Locale.GetText ("Default constructor not found for type " + FullName));
106                         }
107
108                         // TODO: .net does more checks in unmanaged land in RuntimeTypeHandle::CreateInstance
109                         if (IsAbstract) {
110                                 throw new MissingMethodException (Locale.GetText ("Cannot create an abstract class '{0}'.", FullName));
111                         }
112
113                         return ctor.InternalInvoke (null, null);
114                 }
115
116                 internal Object CheckValue (Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
117                 {
118                         bool failed = false;
119                         var res = TryConvertToType (value, ref failed);
120                         if (!failed)
121                                 return res;
122
123                         if ((invokeAttr & BindingFlags.ExactBinding) == BindingFlags.ExactBinding)
124                                 throw new ArgumentException(String.Format(CultureInfo.CurrentUICulture, Environment.GetResourceString("Arg_ObjObjEx"), value.GetType(), this));
125
126                         if (binder != null && binder != Type.DefaultBinder)
127                                 return binder.ChangeType (value, this, culture);
128
129                         throw new ArgumentException(String.Format(CultureInfo.CurrentUICulture, Environment.GetResourceString("Arg_ObjObjEx"), value.GetType(), this));
130                 }
131
132                 object TryConvertToType (object value, ref bool failed)
133                 {
134                         if (IsInstanceOfType (value)) {
135                                 return value;
136                         }
137
138                         if (IsByRef) {
139                                 var elementType = GetElementType ();
140                                 if (value == null || elementType.IsInstanceOfType (value)) {
141                                         return value;
142                                 }
143                         }
144
145                         if (value == null)
146                                 return value;
147
148                         if (IsEnum) {
149                                 var type = Enum.GetUnderlyingType (this);
150                                 if (type == value.GetType ())
151                                         return value;
152                                 var res = IsConvertibleToPrimitiveType (value, this);
153                                 if (res != null)
154                                         return res;
155                         } else if (IsPrimitive) {
156                                 var res = IsConvertibleToPrimitiveType (value, this);
157                                 if (res != null)
158                                         return res;
159                         } else if (IsPointer) {
160                                 var vtype = value.GetType ();
161                                 if (vtype == typeof (IntPtr) || vtype == typeof (UIntPtr))
162                                         return value;
163                         }
164
165                         failed = true;
166                         return null;
167                 }
168
169                 // Binder uses some incompatible conversion rules. For example
170                 // int value cannot be used with decimal parameter but in other
171                 // ways it's more flexible than normal convertor, for example
172                 // long value can be used with int based enum
173                 static object IsConvertibleToPrimitiveType (object value, Type targetType)
174                 {
175                         var type = value.GetType ();
176                         if (type.IsEnum) {
177                                 type = Enum.GetUnderlyingType (type);
178                                 if (type == targetType)
179                                         return value;
180                         }
181
182                         var from = Type.GetTypeCode (type);
183                         var to = Type.GetTypeCode (targetType);
184
185                         switch (to) {
186                                 case TypeCode.Char:
187                                         switch (from) {
188                                                 case TypeCode.Byte:
189                                                         return (Char) (Byte) value;
190                                                 case TypeCode.UInt16:
191                                                         return value;
192                                         }
193                                         break;
194                                 case TypeCode.Int16:
195                                         switch (from) {
196                                                 case TypeCode.Byte:
197                                                         return (Int16) (Byte) value;
198                                                 case TypeCode.SByte:
199                                                         return (Int16) (SByte) value;
200                                         }
201                                         break;
202                                 case TypeCode.UInt16:
203                                         switch (from) {
204                                                 case TypeCode.Byte:
205                                                         return (UInt16) (Byte) value;
206                                                 case TypeCode.Char:
207                                                         return value;
208                                         }
209                                         break;
210                                 case TypeCode.Int32:
211                                         switch (from) {
212                                                 case TypeCode.Byte:
213                                                         return (Int32) (Byte) value;
214                                                 case TypeCode.SByte:
215                                                         return (Int32) (SByte) value;
216                                                 case TypeCode.Char:
217                                                         return (Int32) (Char) value;
218                                                 case TypeCode.Int16:
219                                                         return (Int32) (Int16) value;
220                                                 case TypeCode.UInt16:
221                                                         return (Int32) (UInt16) value;
222                                         }
223                                         break;
224                                 case TypeCode.UInt32:
225                                         switch (from) {
226                                                 case TypeCode.Byte:
227                                                         return (UInt32) (Byte) value;
228                                                 case TypeCode.Char:
229                                                         return (UInt32) (Char) value;
230                                                 case TypeCode.UInt16:
231                                                         return (UInt32) (UInt16) value;
232                                         }
233                                         break;
234                                 case TypeCode.Int64:
235                                         switch (from) {
236                                                 case TypeCode.Byte:
237                                                         return (Int64) (Byte) value;
238                                                 case TypeCode.SByte:
239                                                         return (Int64) (SByte) value;
240                                                 case TypeCode.Int16:
241                                                         return (Int64) (Int16) value;
242                                                 case TypeCode.Char:
243                                                         return (Int64) (Char) value;
244                                                 case TypeCode.UInt16:
245                                                         return (Int64) (UInt16) value;
246                                                 case TypeCode.Int32:
247                                                         return (Int64) (Int32) value;
248                                                 case TypeCode.UInt32:
249                                                         return (Int64) (UInt32) value;
250                                         }
251                                         break;
252                                 case TypeCode.UInt64:
253                                         switch (from) {
254                                                 case TypeCode.Byte:
255                                                         return (UInt64) (Byte) value;
256                                                 case TypeCode.Char:
257                                                         return (UInt64) (Char) value;
258                                                 case TypeCode.UInt16:
259                                                         return (UInt64) (UInt16) value;
260                                                 case TypeCode.UInt32:
261                                                         return (UInt64) (UInt32) value;
262                                         }
263                                         break;
264                                 case TypeCode.Single:
265                                         switch (from) {
266                                                 case TypeCode.Byte:
267                                                         return (Single) (Byte) value;
268                                                 case TypeCode.SByte:
269                                                         return (Single) (SByte) value;
270                                                 case TypeCode.Int16:
271                                                         return (Single) (Int16) value;
272                                                 case TypeCode.Char:
273                                                         return (Single) (Char) value;
274                                                 case TypeCode.UInt16:
275                                                         return (Single) (UInt16) value;
276                                                 case TypeCode.Int32:
277                                                         return (Single) (Int32) value;
278                                                 case TypeCode.UInt32:
279                                                         return (Single) (UInt32) value;
280                                                 case TypeCode.Int64:
281                                                         return (Single) (Int64) value;
282                                                 case TypeCode.UInt64:
283                                                         return (Single) (UInt64) value;
284                                         }
285                                         break;
286                                 case TypeCode.Double:
287                                         switch (from) {
288                                                 case TypeCode.Byte:
289                                                         return (Double) (Byte) value;
290                                                 case TypeCode.SByte:
291                                                         return (Double) (SByte) value;
292                                                 case TypeCode.Char:
293                                                         return (Double) (Char) value;
294                                                 case TypeCode.Int16:
295                                                         return (Double) (Int16) value;
296                                                 case TypeCode.UInt16:
297                                                         return (Double) (UInt16) value;
298                                                 case TypeCode.Int32:
299                                                         return (Double) (Int32) value;
300                                                 case TypeCode.UInt32:
301                                                         return (Double) (UInt32) value;
302                                                 case TypeCode.Int64:
303                                                         return (Double) (Int64) value;
304                                                 case TypeCode.UInt64:
305                                                         return (Double) (UInt64) value;
306                                                 case TypeCode.Single:
307                                                         return (Double) (Single) value;
308                                         }
309                                         break;
310                         }
311
312                         // Everything else is rejected
313                         return null;
314                 }
315
316                 string GetCachedName (TypeNameKind kind)
317                 {
318                         switch (kind) {
319                         case TypeNameKind.SerializationName:
320                                 return ToString ();
321                         default:
322                                 throw new NotImplementedException ();
323                         }
324                 }
325
326                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
327                 extern Type make_array_type (int rank);
328
329                 public override Type MakeArrayType ()
330                 {
331                         return make_array_type (0);
332                 }
333
334                 public override Type MakeArrayType (int rank)
335                 {
336                         if (rank < 1 || rank > 255)
337                                 throw new IndexOutOfRangeException ();
338                         return make_array_type (rank);
339                 }
340
341                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
342                 extern Type make_byref_type ();
343
344                 public override Type MakeByRefType ()
345                 {
346                         if (IsByRef)
347                                 throw new TypeLoadException ("Can not call MakeByRefType on a ByRef type");
348                         return make_byref_type ();
349                 }
350
351                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
352                 static extern Type MakePointerType (Type type);
353
354                 public override Type MakePointerType ()
355                 {
356                         return MakePointerType (this);
357                 }
358
359                 public override StructLayoutAttribute StructLayoutAttribute {
360                         get {
361                                 return GetStructLayoutAttribute ();
362                         }
363                 }
364
365                 public override bool ContainsGenericParameters {
366                         get {
367                                 if (IsGenericParameter)
368                                         return true;
369
370                                 if (IsGenericType) {
371                                         foreach (Type arg in GetGenericArguments ())
372                                                 if (arg.ContainsGenericParameters)
373                                                         return true;
374                                 }
375
376                                 if (HasElementType)
377                                         return GetElementType ().ContainsGenericParameters;
378
379                                 return false;
380                         }
381                 }
382
383                 public override Type[] GetGenericParameterConstraints()
384                 {
385                         if (!IsGenericParameter)
386                                 throw new InvalidOperationException(Environment.GetResourceString("Arg_NotGenericParameter"));
387                         Contract.EndContractBlock();
388
389                         Type[] constraints = GetGenericParameterConstraints_impl ();
390
391                         if (constraints == null)
392                                 constraints = EmptyArray<Type>.Value;
393
394                         return constraints;
395                 }
396
397                 internal static object CreateInstanceForAnotherGenericParameter (Type genericType, RuntimeType genericArgument)
398                 {
399                         var gt = (RuntimeType) MakeGenericType (genericType, new Type [] { genericArgument });
400                         var ctor = gt.GetDefaultConstructor ();
401                         return ctor.InternalInvoke (null, null);
402                 }
403
404                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
405                 static extern Type MakeGenericType (Type gt, Type [] types);
406
407                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
408                 internal extern RuntimeMethodInfo[] GetMethodsByName (string name, BindingFlags bindingAttr, bool ignoreCase, Type reflected_type);
409
410                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
411                 extern RuntimePropertyInfo[] GetPropertiesByName (string name, BindingFlags bindingAttr, bool icase, Type reflected_type);              
412
413                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
414                 extern RuntimeConstructorInfo[] GetConstructors_internal (BindingFlags bindingAttr, Type reflected_type);
415
416                 public override InterfaceMapping GetInterfaceMap (Type ifaceType)
417                 {
418                         if (IsGenericParameter)
419                                 throw new InvalidOperationException(Environment.GetResourceString("Arg_GenericParameter"));
420                 
421                         if ((object)ifaceType == null)
422                                 throw new ArgumentNullException("ifaceType");
423                         Contract.EndContractBlock();
424
425                         RuntimeType ifaceRtType = ifaceType as RuntimeType;
426
427                         if (ifaceRtType == null)
428                                 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "ifaceType");
429
430                         InterfaceMapping res;
431                         if (!ifaceType.IsInterface)
432                                 throw new ArgumentException (Locale.GetText ("Argument must be an interface."), "ifaceType");
433                         if (IsInterface)
434                                 throw new ArgumentException ("'this' type cannot be an interface itself");
435                         res.TargetType = this;
436                         res.InterfaceType = ifaceType;
437                         GetInterfaceMapData (this, ifaceType, out res.TargetMethods, out res.InterfaceMethods);
438                         if (res.TargetMethods == null)
439                                 throw new ArgumentException (Locale.GetText ("Interface not found"), "ifaceType");
440
441                         return res;
442                 }
443
444                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
445                 static extern void GetInterfaceMapData (Type t, Type iface, out MethodInfo[] targets, out MethodInfo[] methods);                
446
447                 public override Guid GUID {
448                         get {
449                                 object[] att = GetCustomAttributes(typeof(System.Runtime.InteropServices.GuidAttribute), true);
450                                 if (att.Length == 0)
451                                         return Guid.Empty;
452                                 return new Guid(((System.Runtime.InteropServices.GuidAttribute)att[0]).Value);
453                         }
454                 }
455
456                 StructLayoutAttribute GetStructLayoutAttribute ()
457                 {
458                         LayoutKind kind;
459
460                         if (IsLayoutSequential)
461                                 kind = LayoutKind.Sequential;
462                         else if (IsExplicitLayout)
463                                 kind = LayoutKind.Explicit;
464                         else
465                                 kind = LayoutKind.Auto;
466
467                         StructLayoutAttribute attr = new StructLayoutAttribute (kind);
468
469                         if (IsUnicodeClass)
470                                 attr.CharSet = CharSet.Unicode;
471                         else if (IsAnsiClass)
472                                 attr.CharSet = CharSet.Ansi;
473                         else
474                                 attr.CharSet = CharSet.Auto;
475
476                         if (kind != LayoutKind.Auto) {
477                                 int packing;
478                                 GetPacking (out packing, out attr.Size);
479                                 // 0 means no data provided, we end up with default value
480                                 if (packing != 0)
481                                         attr.Pack = packing;
482                         }
483
484                         return attr;
485                 }
486
487                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
488                 extern void GetPacking (out int packing, out int size);
489
490 #if MONO_COM
491                 private static Dictionary<Guid, Type> clsid_types;
492                 private static AssemblyBuilder clsid_assemblybuilder;
493 #endif
494
495                 internal static Type GetTypeFromCLSIDImpl(Guid clsid, String server, bool throwOnError)
496                 {
497 #if MONO_COM
498                         Type result;
499
500                         if (clsid_types == null)
501                         {
502                                 Dictionary<Guid, Type> new_clsid_types = new Dictionary<Guid, Type> ();
503                                 Interlocked.CompareExchange<Dictionary<Guid, Type>>(
504                                         ref clsid_types, new_clsid_types, null);
505                         }
506
507                         lock (clsid_types) {
508                                 if (clsid_types.TryGetValue(clsid, out result))
509                                         return result;
510
511                                 if (clsid_assemblybuilder == null)
512                                 {
513                                         AssemblyName assemblyname = new AssemblyName ();
514                                         assemblyname.Name = "GetTypeFromCLSIDDummyAssembly";
515                                         clsid_assemblybuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (
516                                                 assemblyname, AssemblyBuilderAccess.Run);
517                                 }
518                                 ModuleBuilder modulebuilder = clsid_assemblybuilder.DefineDynamicModule (
519                                         clsid.ToString ());
520
521                                 TypeBuilder typebuilder = modulebuilder.DefineType ("System.__ComObject",
522                                         TypeAttributes.Public | TypeAttributes.Class, typeof(System.__ComObject));
523
524                                 Type[] guidattrtypes = new Type[] { typeof(string) };
525
526                                 CustomAttributeBuilder customattr = new CustomAttributeBuilder (
527                                         typeof(GuidAttribute).GetConstructor (guidattrtypes),
528                                         new object[] { clsid.ToString () });
529
530                                 typebuilder.SetCustomAttribute (customattr);
531
532                                 customattr = new CustomAttributeBuilder (
533                                         typeof(ComImportAttribute).GetConstructor (EmptyTypes),
534                                         new object[0] {});
535
536                                 typebuilder.SetCustomAttribute (customattr);
537
538                                 result = typebuilder.CreateType ();
539
540                                 clsid_types.Add(clsid, result);
541
542                                 return result;
543                         }
544 #else
545                         throw new NotImplementedException ("Unmanaged activation removed");
546 #endif
547                 }
548
549                 protected override TypeCode GetTypeCodeImpl ()
550                 {
551                         return GetTypeCodeImplInternal (this);
552                 }
553
554                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
555                 extern static TypeCode GetTypeCodeImplInternal (Type type);             
556
557                 internal static Type GetTypeFromProgIDImpl(String progID, String server, bool throwOnError)
558                 {
559                         throw new NotImplementedException ("Unmanaged activation is not supported");
560                 }
561
562                 public override string ToString()
563                 {
564                         return getFullName (false, false);
565                 }
566
567                 bool IsGenericCOMObjectImpl ()
568                 {
569                         return false;
570                 }
571
572                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
573                 static extern object CreateInstanceInternal (Type type);
574
575                 public extern override MethodBase DeclaringMethod {
576                         [MethodImplAttribute(MethodImplOptions.InternalCall)]
577                         get;
578                 }               
579                 
580                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
581                 internal extern string getFullName(bool full_name, bool assembly_qualified);
582
583                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
584                 extern Type[] GetGenericArgumentsInternal (bool runtimeArray);
585
586                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
587                 extern GenericParameterAttributes GetGenericParameterAttributes ();
588
589                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
590                 extern Type[] GetGenericParameterConstraints_impl ();
591
592                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
593                 extern int GetGenericParameterPosition ();
594
595                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
596                 extern RuntimeEventInfo[] GetEvents_internal (string name, BindingFlags bindingAttr, Type reflected_type);
597
598                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
599                 extern RuntimeFieldInfo[] GetFields_internal (string name, BindingFlags bindingAttr, Type reflected_type);
600
601                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
602                 public extern override Type[] GetInterfaces();
603
604                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
605                 extern RuntimeType[] GetNestedTypes_internal (string name, BindingFlags bindingAttr);           
606
607                 public override string AssemblyQualifiedName {
608                         get {
609                                 return getFullName (true, true);
610                         }
611                 }
612
613                 public extern override Type DeclaringType {
614                         [MethodImplAttribute(MethodImplOptions.InternalCall)]
615                         get;
616                 }
617
618                 public override string FullName {
619                         get {
620                                 throw new NotImplementedException ();
621                         }
622                 }
623
624                 public extern override string Name {
625                         [MethodImplAttribute(MethodImplOptions.InternalCall)]
626                         get;
627                 }
628
629                 public extern override string Namespace {
630                         [MethodImplAttribute(MethodImplOptions.InternalCall)]
631                         get;
632                 }
633
634                 //seclevel { transparent = 0, safe-critical = 1, critical = 2}
635                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
636                 public extern int get_core_clr_security_level ();
637
638                 public override bool IsSecurityTransparent {
639                         get { return get_core_clr_security_level () == 0; }
640                 }
641
642                 public override bool IsSecurityCritical {
643                         get { return get_core_clr_security_level () > 0; }
644                 }
645
646                 public override bool IsSecuritySafeCritical {
647                         get { return get_core_clr_security_level () == 1; }
648                 }               
649         }
650 }