diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index e75a0fc2e4f3..1f30acaf0ae1 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -137,7 +137,7 @@ - + diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 79a5866ef80d..9999b5480315 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -192,6 +192,7 @@ + diff --git a/src/System.Private.CoreLib/shared/System/Delegate.cs b/src/System.Private.CoreLib/shared/System/Delegate.cs new file mode 100644 index 000000000000..d4db0f2dff8c --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Delegate.cs @@ -0,0 +1,126 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization; + +namespace System +{ + public abstract partial class Delegate : ICloneable, ISerializable + { + private Delegate() + { + } + + public virtual object Clone() => MemberwiseClone(); + + public static Delegate Combine(Delegate a, Delegate b) + { + if (a is null) + return b; + + return a.CombineImpl(b); + } + + public static Delegate Combine(params Delegate[] delegates) + { + if (delegates is null || delegates.Length == 0) + return null; + + Delegate d = delegates [0]; + for (int i = 1; i < delegates.Length; i++) + d = Combine(d, delegates[i]); + + return d; + } + + protected virtual Delegate CombineImpl(Delegate d) => throw new MulticastNotSupportedException(SR.Multicast_Combine); + + // V2 api: Creates open or closed delegates to static or instance methods - relaxed signature checking allowed. + public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method) => CreateDelegate(type, firstArgument, method, throwOnBindFailure: true); + + // V1 api: Creates open delegates to static or instance methods - relaxed signature checking allowed. + public static Delegate CreateDelegate(Type type, MethodInfo method) => CreateDelegate(type, method, throwOnBindFailure: true); + + // V1 api: Creates closed delegates to instance methods only, relaxed signature checking disallowed. + public static Delegate CreateDelegate(Type type, object target, string method) => CreateDelegate(type, target, method, ignoreCase: false, throwOnBindFailure: true); + public static Delegate CreateDelegate(Type type, object target, string method, bool ignoreCase) => CreateDelegate(type, target, method, ignoreCase, throwOnBindFailure: true); + + // V1 api: Creates open delegates to static methods only, relaxed signature checking disallowed. + public static Delegate CreateDelegate(Type type, Type target, string method) => CreateDelegate(type, target, method, ignoreCase: false, throwOnBindFailure: true); + public static Delegate CreateDelegate(Type type, Type target, string method, bool ignoreCase) => CreateDelegate(type, target, method, ignoreCase, throwOnBindFailure: true); + + public object DynamicInvoke(params object[] args) + { + return DynamicInvokeImpl(args); + } + + public virtual Delegate[] GetInvocationList() => new Delegate[] { this }; + + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) => throw new PlatformNotSupportedException(); + + public MethodInfo Method => GetMethodImpl(); + + protected virtual Delegate RemoveImpl(Delegate d) => d.Equals(this) ? null : this; + + public static Delegate Remove(Delegate source, Delegate value) + { + if (source == null) + return null; + + if (value == null) + return source; + + if (!InternalEqualTypes(source, value)) + throw new ArgumentException(SR.Arg_DlgtTypeMis); + + return source.RemoveImpl(value); + } + + public static Delegate RemoveAll(Delegate source, Delegate value) + { + Delegate newDelegate = null; + + do + { + newDelegate = source; + source = Remove(source, value); + } + while (newDelegate != source); + + return newDelegate; + } + + // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Delegate d1, Delegate d2) + { + // Test d2 first to allow branch elimination when inlined for null checks (== null) + // so it can become a simple test + if (d2 is null) + { + // return true/false not the test result https://github.com/dotnet/coreclr/issues/914 + return (d1 is null) ? true : false; + } + + return ReferenceEquals(d2, d1) || d2.Equals((object)d1); + } + + // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Delegate d1, Delegate d2) + { + // Test d2 first to allow branch elimination when inlined for not null checks (!= null) + // so it can become a simple test + if (d2 is null) + { + // return true/false not the test result https://github.com/dotnet/coreclr/issues/914 + return (d1 is null) ? false : true; + } + + return ReferenceEquals(d2, d1) ? false : !d2.Equals(d1); + } + } +} \ No newline at end of file diff --git a/src/System.Private.CoreLib/src/System/Delegate.cs b/src/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs similarity index 82% rename from src/System.Private.CoreLib/src/System/Delegate.cs rename to src/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs index df9bac476646..f0e7d09f7013 100644 --- a/src/System.Private.CoreLib/src/System/Delegate.cs +++ b/src/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs @@ -12,7 +12,7 @@ namespace System { [ClassInterface(ClassInterfaceType.None)] [ComVisible(true)] - public abstract class Delegate : ICloneable, ISerializable + public abstract partial class Delegate : ICloneable, ISerializable { // _target is the object we will invoke on internal object _target; @@ -84,22 +84,6 @@ protected Delegate(Type target, string method) DelegateBindingFlags.CaselessMatching); } - // Protect the default constructor so you can't build a delegate - private Delegate() - { - } - - public object DynamicInvoke(params object[] args) - { - // Theoretically we should set up a LookForMyCaller stack mark here and pass that along. - // But to maintain backward compatibility we can't switch to calling an - // internal overload of DynamicInvokeImpl that takes a stack mark. - // Fortunately the stack walker skips all the reflection invocation frames including this one. - // So this method will never be returned by the stack walker as the caller. - // See SystemDomain::CallersMethodCallbackWithStackMark in AppDomain.cpp. - return DynamicInvokeImpl(args); - } - protected virtual object DynamicInvokeImpl(object[] args) { RuntimeMethodHandleInternal method = new RuntimeMethodHandleInternal(GetInvokeMethod()); @@ -177,42 +161,6 @@ public override int GetHashCode() return GetType().GetHashCode(); } - public static Delegate Combine(Delegate a, Delegate b) - { - if ((object)a == null) // cast to object for a more efficient test - return b; - - return a.CombineImpl(b); - } - - public static Delegate Combine(params Delegate[] delegates) - { - if (delegates == null || delegates.Length == 0) - return null; - - Delegate d = delegates[0]; - for (int i = 1; i < delegates.Length; i++) - d = Combine(d, delegates[i]); - - return d; - } - - public virtual Delegate[] GetInvocationList() - { - Delegate[] d = new Delegate[1]; - d[0] = this; - return d; - } - - // This routine will return the method - public MethodInfo Method - { - get - { - return GetMethodImpl(); - } - } - protected virtual MethodInfo GetMethodImpl() { if ((_methodBase == null) || !(_methodBase is MethodInfo)) @@ -276,63 +224,6 @@ public object Target } } - - public static Delegate Remove(Delegate source, Delegate value) - { - if (source == null) - return null; - - if (value == null) - return source; - - if (!InternalEqualTypes(source, value)) - throw new ArgumentException(SR.Arg_DlgtTypeMis); - - return source.RemoveImpl(value); - } - - public static Delegate RemoveAll(Delegate source, Delegate value) - { - Delegate newDelegate = null; - - do - { - newDelegate = source; - source = Remove(source, value); - } - while (newDelegate != source); - - return newDelegate; - } - - protected virtual Delegate CombineImpl(Delegate d) - { - throw new MulticastNotSupportedException(SR.Multicast_Combine); - } - - protected virtual Delegate RemoveImpl(Delegate d) - { - return (d.Equals(this)) ? null : this; - } - - - public virtual object Clone() - { - return MemberwiseClone(); - } - - // V1 API. - public static Delegate CreateDelegate(Type type, object target, string method) - { - return CreateDelegate(type, target, method, false, true); - } - - // V1 API. - public static Delegate CreateDelegate(Type type, object target, string method, bool ignoreCase) - { - return CreateDelegate(type, target, method, ignoreCase, true); - } - // V1 API. public static Delegate CreateDelegate(Type type, object target, string method, bool ignoreCase, bool throwOnBindFailure) { @@ -371,18 +262,6 @@ public static Delegate CreateDelegate(Type type, object target, string method, b return d; } - // V1 API. - public static Delegate CreateDelegate(Type type, Type target, string method) - { - return CreateDelegate(type, target, method, false, true); - } - - // V1 API. - public static Delegate CreateDelegate(Type type, Type target, string method, bool ignoreCase) - { - return CreateDelegate(type, target, method, ignoreCase, true); - } - // V1 API. public static Delegate CreateDelegate(Type type, Type target, string method, bool ignoreCase, bool throwOnBindFailure) { @@ -462,12 +341,6 @@ public static Delegate CreateDelegate(Type type, MethodInfo method, bool throwOn return d; } - // V2 API. - public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method) - { - return CreateDelegate(type, firstArgument, method, true); - } - // V2 API. public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method, bool throwOnBindFailure) { @@ -505,43 +378,6 @@ public static Delegate CreateDelegate(Type type, object firstArgument, MethodInf return d; } - // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Delegate d1, Delegate d2) - { - // Test d2 first to allow branch elimination when inlined for null checks (== null) - // so it can become a simple test - if (d2 is null) - { - // return true/false not the test result https://github.com/dotnet/coreclr/issues/914 - return (d1 is null) ? true : false; - } - - return ReferenceEquals(d2, d1) ? true : d2.Equals((object)d1); - } - - public static bool operator !=(Delegate d1, Delegate d2) - { - // Test d2 first to allow branch elimination when inlined for not null checks (!= null) - // so it can become a simple test - if (d2 is null) - { - // return true/false not the test result https://github.com/dotnet/coreclr/issues/914 - return (d1 is null) ? false : true; - } - - return ReferenceEquals(d2, d1) ? false : !d2.Equals(d1); - } - - // - // Implementation of ISerializable - // - - public virtual void GetObjectData(SerializationInfo info, StreamingContext context) - { - throw new PlatformNotSupportedException(); - } - // // internal implementation details (FCALLS and utilities) // @@ -614,12 +450,6 @@ internal static Delegate CreateDelegateNoSecurityCheck(RuntimeType type, object return d; } - // V1 API. - public static Delegate CreateDelegate(Type type, MethodInfo method) - { - return CreateDelegate(type, method, true); - } - internal static Delegate CreateDelegateInternal(RuntimeType rtType, RuntimeMethodInfo rtMethod, object firstArgument, DelegateBindingFlags flags) { Delegate d = InternalAlloc(rtType);