Delegate.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Diagnostics.CodeAnalysis;
  5. using System.Reflection;
  6. using System.Runtime.CompilerServices;
  7. using System.Runtime.Serialization;
  8. namespace System
  9. {
  10. public abstract partial class Delegate : ICloneable, ISerializable
  11. {
  12. public virtual object Clone() => MemberwiseClone();
  13. [return: NotNullIfNotNull("a")]
  14. [return: NotNullIfNotNull("b")]
  15. public static Delegate? Combine(Delegate? a, Delegate? b)
  16. {
  17. if (a is null)
  18. return b;
  19. return a.CombineImpl(b);
  20. }
  21. public static Delegate? Combine(params Delegate?[]? delegates)
  22. {
  23. if (delegates == null || delegates.Length == 0)
  24. return null;
  25. Delegate? d = delegates[0];
  26. for (int i = 1; i < delegates.Length; i++)
  27. d = Combine(d, delegates[i]);
  28. return d;
  29. }
  30. // V2 api: Creates open or closed delegates to static or instance methods - relaxed signature checking allowed.
  31. public static Delegate CreateDelegate(Type type, object? firstArgument, MethodInfo method) => CreateDelegate(type, firstArgument, method, throwOnBindFailure: true)!;
  32. // V1 api: Creates open delegates to static or instance methods - relaxed signature checking allowed.
  33. public static Delegate CreateDelegate(Type type, MethodInfo method) => CreateDelegate(type, method, throwOnBindFailure: true)!;
  34. // V1 api: Creates closed delegates to instance methods only, relaxed signature checking disallowed.
  35. public static Delegate CreateDelegate(Type type, object target, string method) => CreateDelegate(type, target, method, ignoreCase: false, throwOnBindFailure: true)!;
  36. public static Delegate CreateDelegate(Type type, object target, string method, bool ignoreCase) => CreateDelegate(type, target, method, ignoreCase, throwOnBindFailure: true)!;
  37. // V1 api: Creates open delegates to static methods only, relaxed signature checking disallowed.
  38. public static Delegate CreateDelegate(Type type, Type target, string method) => CreateDelegate(type, target, method, ignoreCase: false, throwOnBindFailure: true)!;
  39. public static Delegate CreateDelegate(Type type, Type target, string method, bool ignoreCase) => CreateDelegate(type, target, method, ignoreCase, throwOnBindFailure: true)!;
  40. #if !CORERT
  41. protected virtual Delegate CombineImpl(Delegate? d) => throw new MulticastNotSupportedException(SR.Multicast_Combine);
  42. protected virtual Delegate? RemoveImpl(Delegate d) => d.Equals(this) ? null : this;
  43. public virtual Delegate[] GetInvocationList() => new Delegate[] { this };
  44. public object? DynamicInvoke(params object?[]? args)
  45. {
  46. return DynamicInvokeImpl(args);
  47. }
  48. #endif
  49. public virtual void GetObjectData(SerializationInfo info, StreamingContext context) => throw new PlatformNotSupportedException();
  50. public MethodInfo Method => GetMethodImpl();
  51. public static Delegate? Remove(Delegate? source, Delegate? value)
  52. {
  53. if (source == null)
  54. return null;
  55. if (value == null)
  56. return source;
  57. if (!InternalEqualTypes(source, value))
  58. throw new ArgumentException(SR.Arg_DlgtTypeMis);
  59. return source.RemoveImpl(value);
  60. }
  61. public static Delegate? RemoveAll(Delegate? source, Delegate? value)
  62. {
  63. Delegate? newDelegate = null;
  64. do
  65. {
  66. newDelegate = source;
  67. source = Remove(source, value);
  68. }
  69. while (newDelegate != source);
  70. return newDelegate;
  71. }
  72. // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
  73. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  74. public static bool operator ==(Delegate? d1, Delegate? d2)
  75. {
  76. // Test d2 first to allow branch elimination when inlined for null checks (== null)
  77. // so it can become a simple test
  78. if (d2 is null)
  79. {
  80. // return true/false not the test result https://github.com/dotnet/coreclr/issues/914
  81. return (d1 is null) ? true : false;
  82. }
  83. return ReferenceEquals(d2, d1) ? true : d2.Equals((object?)d1);
  84. }
  85. // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
  86. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  87. public static bool operator !=(Delegate? d1, Delegate? d2)
  88. {
  89. // Test d2 first to allow branch elimination when inlined for not null checks (!= null)
  90. // so it can become a simple test
  91. if (d2 is null)
  92. {
  93. // return true/false not the test result https://github.com/dotnet/coreclr/issues/914
  94. return (d1 is null) ? false : true;
  95. }
  96. return ReferenceEquals(d2, d1) ? false : !d2.Equals(d1);
  97. }
  98. }
  99. }