diff --git a/src/HotAvalonia/HotAvalonia.csproj b/src/HotAvalonia/HotAvalonia.csproj
index 56fc55a..4635a8e 100644
--- a/src/HotAvalonia/HotAvalonia.csproj
+++ b/src/HotAvalonia/HotAvalonia.csproj
@@ -16,14 +16,16 @@
+
+
-
-
+
+
diff --git a/src/HotAvalonia/Reflection/Inject/MethodInjector.cs b/src/HotAvalonia/Reflection/Inject/MethodInjector.cs
index 6730c9b..47585f0 100644
--- a/src/HotAvalonia/Reflection/Inject/MethodInjector.cs
+++ b/src/HotAvalonia/Reflection/Inject/MethodInjector.cs
@@ -34,7 +34,7 @@ internal static class MethodInjector
///
public static IInjection Inject(MethodBase source, MethodInfo replacement) => InjectionType switch
{
- InjectionType.Native => new NativeInjection(source, replacement),
+ InjectionType.Native => NativeInjection.Create(source, replacement),
_ => ThrowNotSupportedException(),
};
@@ -72,60 +72,105 @@ private static InjectionType DetectSupportedInjectionType()
if (IsDisabled())
return InjectionType.None;
- try
- {
- // Enable dynamic code generation, which is required for MonoMod to function.
- using IDisposable context = AssemblyHelper.ForceAllowDynamicCode();
-
- // `PlatformTriple.Current` may throw exceptions such as:
- // - NotImplementedException
- // - PlatformNotSupportedException
- // - etc.
- // This happens if the current environment is not (yet) supported.
- if (PlatformTriple.Current is not null)
- return InjectionType.Native;
- }
- catch { }
-
- return InjectionType.None;
+ return NativeInjection.IsSupported ? InjectionType.Native : InjectionType.None;
}
}
///
/// Provides functionality to inject a replacement method using native code hooks.
///
-file sealed class NativeInjection : IInjection
+file static class NativeInjection
{
///
- /// The hook used for the method injection.
+ /// Injects a replacement method implementation for the specified source method.
///
- private readonly Hook _hook;
+ /// The method to be replaced.
+ /// The replacement method implementation.
+ /// An instance representing the method injection.
+ public static IInjection Create(MethodBase source, MethodInfo replacement)
+ => new MonoModInjection(source, replacement);
///
- /// Initializes a new instance of the class.
+ /// Indicates whether native method injections are supported in the current runtime environment.
///
- /// The method to be replaced.
- /// The replacement method implementation.
- public NativeInjection(MethodBase source, MethodInfo replacement)
+ public static bool IsSupported
{
- // Enable dynamic code generation, which is required for MonoMod to function.
- // Note that we cannot enable it forcefully just once and call it a day,
- // because this only affects the current thread.
- _ = AssemblyHelper.ForceAllowDynamicCode();
-
- _hook = new(source, replacement, applyByDefault: true);
+ get
+ {
+ try
+ {
+ // If `MonoMod.RuntimeDetour` is not present,
+ // this will result in `TypeLoadException`,
+ // that's why we need this wrapper.
+ return MonoModInjection.IsSupported;
+ }
+ catch
+ {
+ return false;
+ }
+ }
}
///
- /// Applies the method injection.
+ /// Represents a MonoMod-based injection.
///
- public void Apply() => _hook.Apply();
+ private sealed class MonoModInjection : IInjection
+ {
+ ///
+ /// The hook used for the method injection.
+ ///
+ private readonly Hook _hook;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The method to be replaced.
+ /// The replacement method implementation.
+ public MonoModInjection(MethodBase source, MethodInfo replacement)
+ {
+ // Enable dynamic code generation, which is required for MonoMod to function.
+ // Note that we cannot enable it forcefully just once and call it a day,
+ // because this only affects the current thread.
+ _ = AssemblyHelper.ForceAllowDynamicCode();
- ///
- /// Reverts all the effects caused by the method injection.
- ///
- public void Undo() => _hook.Undo();
+ _hook = new(source, replacement, applyByDefault: true);
+ }
- ///
- public void Dispose() => _hook.Dispose();
+ ///
+ /// Indicates whether MonoMod is supported in the current environment.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static bool IsSupported
+ {
+ get
+ {
+ // Enable dynamic code generation, which is required for MonoMod to function.
+ using IDisposable context = AssemblyHelper.ForceAllowDynamicCode();
+
+ // `PlatformTriple.Current` may throw exceptions such as:
+ // - NotImplementedException
+ // - PlatformNotSupportedException
+ // - etc.
+ // This happens if the current environment is not (yet) supported.
+ return PlatformTriple.Current is not null;
+ }
+ }
+
+ ///
+ /// Applies the method injection.
+ ///
+ public void Apply() => _hook.Apply();
+
+ ///
+ /// Reverts all the effects caused by the method injection.
+ ///
+ public void Undo() => _hook.Undo();
+
+ ///
+ public void Dispose() => _hook.Dispose();
+ }
}