Dose not work net core 2.1
Shim classShim = Shim.Replace(() => Console.WriteLine(Is.A<string>())).With(
delegate (string s) {
Console.WriteLine("here");
});
Console.WriteLine("test");
Confirmed, this does not work either:
Shim.Replace(() => TimeZoneInfo.Local).With(() => TimeZoneInfo.Utc);
It's not completely broken in .NET Core 2.1, but there are some really interesting things specific to the low-level CLR magic that .NET Core has subscribed to, which I think Pose would have to work around in order to keep working the way it does in a ton of cases that don't even appear to be all that complex (on the surface).
I'm not in any way affiliated with this project (it just got linked from a Reddit thread, and I was intrigued), but I think the basic idea would be to maintain a list of methods that are implemented as JIT intrinsics and skip rewriting them unless the user explicitly provided an override.
The below code throws an InvalidProgramException, which other threads seem to have touched on, but that's not actually the interesting part of it. I've included a Ben.Demystifier-processed stack trace so you can follow along (all links go to dotnet/coreclr as of tag "v2.1.11", in case you want to browse around it more):
- Things started to go south right around Pose's rewrite of this line, which is a simple implicit cast from
System.StringtoSystem.ReadOnlySpan<char>. - It eventually got to Pose's rewrite of this one a few entries up the stack trace. See the comment: Pose does all its magic using reflection.
- This same kind of pattern actually occurred again in the same stack trace, while running the rewritten constructor for that exception, on the rewritten version of this.
- The bit that finally wound up throwing
InvalidProgramExceptionwas the rewrite of this method.
Here's the source code so you can mess around with it:
ConsoleApp0.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Pose" Version="1.2.1" />
<PackageReference Include="Ben.Demystifier" Version="0.1.4" />
</ItemGroup>
</Project>
global.json
{
"sdk": {
"version": "2.1.604"
}
}
Program.cs
using System;
using System.Diagnostics;
using System.Runtime.ExceptionServices;
using Pose;
class Program
{
static void Main()
{
try
{
// writes my actual local offset:
Console.WriteLine(TimeZoneInfo.Local.BaseUtcOffset);
TimeSpan overriddenOffset = default;
PoseContext.Isolate(() => overriddenOffset = TimeZoneInfo.Local.BaseUtcOffset,
Shim.Replace(() => TimeZoneInfo.Local).With(() => TimeZoneInfo.Utc));
// writes "00:00:00":
Console.WriteLine(overriddenOffset);
// writes my actual local offset again:
Console.WriteLine(TimeZoneInfo.Local.BaseUtcOffset);
// throws an error with the stack trace I'm going to paste:
PoseContext.Isolate(() => Console.WriteLine(TimeZoneInfo.Local.BaseUtcOffset),
Shim.Replace(() => TimeZoneInfo.Local).With(() => TimeZoneInfo.Utc));
}
catch (Exception ex)
{
ExceptionDispatchInfo.Capture(ex.Demystify()).Throw();
}
}
}
Stack Trace:
Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidProgramException: Common Language Runtime detected an invalid program.
at int dynamic_System.Collections.Generic.GenericEqualityComparer`1[System.String]_LastIndexOf(GenericEqualityComparer<string>, string[], string, int, int)
at int stub_virt_System.Collections.Generic.EqualityComparer`1[System.String]_LastIndexOf(EqualityComparer<string>, string[], string, int, int, RuntimeMethodHandle, RuntimeTypeHandle)
at int dynamic_System.Array_LastIndexOf(string[], string, int, int)
at int stub_System.Array_LastIndexOf(string[], string, int, int, RuntimeMethodHandle, RuntimeTypeHandle)
at int dynamic_System.Collections.Generic.List`1[System.String]_LastIndexOf(List<string>, string, int, int)
at int stub_System.Collections.Generic.List`1[System.String]_LastIndexOf(List<string>, string, int, int, RuntimeMethodHandle, RuntimeTypeHandle)
at int dynamic_System.Collections.Generic.List`1[System.String]_LastIndexOf(List<string>, string)
at int stub_virt_System.Collections.Generic.List`1[System.String]_LastIndexOf(List<string>, string, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.SR_InternalGetResourceString(string)
at string stub_System.SR_InternalGetResourceString(string, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.SR_GetResourceString(string, string)
at string stub_System.SR_GetResourceString(string, string, RuntimeMethodHandle, RuntimeTypeHandle)
at string stub_System.SR_get_Arg_PlatformNotSupported(RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.PlatformNotSupportedException_.ctor(PlatformNotSupportedException)
at PlatformNotSupportedException stub_ctor_System.PlatformNotSupportedException_.ctor(RuntimeMethodHandle, RuntimeTypeHandle)
at Byte& dynamic_Internal.Runtime.CompilerServices.Unsafe_As(ref char)
at Byte& stub_Internal.Runtime.CompilerServices.Unsafe_As(ref char, RuntimeMethodHandle, RuntimeTypeHandle)
at bool dynamic_System.String_EqualsHelper(string, string)
at bool stub_System.String_EqualsHelper(string, string, RuntimeMethodHandle, RuntimeTypeHandle)
at bool stub_System.String_Equals(string, string, RuntimeMethodHandle, RuntimeTypeHandle)
at bool stub_System.String_op_Equality(string, string, RuntimeMethodHandle, RuntimeTypeHandle)
at ResourceSet dynamic_System.Resources.ResourceManager_GetFirstResourceSet(ResourceManager, CultureInfo)
at ResourceSet stub_System.Resources.ResourceManager_GetFirstResourceSet(ResourceManager, CultureInfo, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.Resources.ResourceManager_GetString(ResourceManager, string, CultureInfo)
at string stub_virt_System.Resources.ResourceManager_GetString(ResourceManager, string, CultureInfo, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.SR_InternalGetResourceString(string)
at string stub_System.SR_InternalGetResourceString(string, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.SR_GetResourceString(string, string)
at string stub_System.SR_GetResourceString(string, string, RuntimeMethodHandle, RuntimeTypeHandle)
at string stub_System.SR_get_Arg_PlatformNotSupported(RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.PlatformNotSupportedException_.ctor(PlatformNotSupportedException)
at PlatformNotSupportedException stub_ctor_System.PlatformNotSupportedException_.ctor(RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.ByReference`1[System.Char]_.ctor(ref ByReference<char>, ref char)
at ByReference<char> stub_ctor_System.ByReference`1[System.Char]_.ctor(ref char, RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.ReadOnlySpan`1[System.Char]_.ctor(ref ReadOnlySpan<char>, ref char, int)
at ReadOnlySpan<char> stub_ctor_System.ReadOnlySpan`1[System.Char]_.ctor(ref char, int, RuntimeMethodHandle, RuntimeTypeHandle)
at ReadOnlySpan<char> dynamic_System.String_op_Implicit(string)
at ReadOnlySpan<char> stub_System.String_op_Implicit(string, RuntimeMethodHandle, RuntimeTypeHandle)
at StringBuilder dynamic_System.Globalization.TimeSpanFormat_FormatToBuilder(TimeSpan, ReadOnlySpan<char>, IFormatProvider)
at StringBuilder stub_System.Globalization.TimeSpanFormat_FormatToBuilder(TimeSpan, ReadOnlySpan<char>, IFormatProvider, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.Globalization.TimeSpanFormat_Format(TimeSpan, string, IFormatProvider)
at string stub_System.Globalization.TimeSpanFormat_Format(TimeSpan, string, IFormatProvider, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.TimeSpan_ToString(ref TimeSpan, string, IFormatProvider)
at string stub_virt_System.IFormattable_ToString(IFormattable, string, IFormatProvider, RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.IO.TextWriter_WriteLine(TextWriter, object)
at void stub_virt_System.IO.TextWriter_WriteLine(TextWriter, object, RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.IO.SyncTextWriter_WriteLine(SyncTextWriter, object)
at void stub_virt_System.IO.TextWriter_WriteLine(TextWriter, object, RuntimeMethodHandle, RuntimeTypeHandle)
at void stub_System.Console_WriteLine(object, RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_Program+<>c_<Main>b__0_3(?)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at Pose.PoseContext.Isolate(Action entryPoint, Shim[] shims)
at Program.Main() in C:\<SNIP>\Program.cs:line 26
--- End of stack trace from previous location where exception was thrown ---
at Program.Main() in C:\<SNIP>\Program.cs:line 31