#region License // Copyright (c) 2007 James Newton-King // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. #endregion #if HAVE_FSHARP_TYPES using System.Threading; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using LC.Newtonsoft.Json.Serialization; using System.Diagnostics; namespace LC.Newtonsoft.Json.Utilities { internal class FSharpFunction { private readonly object? _instance; private readonly MethodCall _invoker; public FSharpFunction(object? instance, MethodCall invoker) { _instance = instance; _invoker = invoker; } public object Invoke(params object[] args) { object o = _invoker(_instance, args); return o; } } internal class FSharpUtils { private FSharpUtils(Assembly fsharpCoreAssembly) { FSharpCoreAssembly = fsharpCoreAssembly; Type fsharpType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpType"); MethodInfo isUnionMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "IsUnion", BindingFlags.Public | BindingFlags.Static); IsUnion = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(isUnionMethodInfo)!; MethodInfo getUnionCasesMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "GetUnionCases", BindingFlags.Public | BindingFlags.Static); GetUnionCases = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(getUnionCasesMethodInfo)!; Type fsharpValue = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpValue"); PreComputeUnionTagReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionTagReader"); PreComputeUnionReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionReader"); PreComputeUnionConstructor = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionConstructor"); Type unionCaseInfo = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.UnionCaseInfo"); GetUnionCaseInfoName = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("Name")!)!; GetUnionCaseInfoTag = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("Tag")!)!; GetUnionCaseInfoDeclaringType = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("DeclaringType")!)!; GetUnionCaseInfoFields = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(unionCaseInfo.GetMethod("GetFields")); Type listModule = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.ListModule"); _ofSeq = listModule.GetMethod("OfSeq"); _mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2"); } private static readonly object Lock = new object(); private static FSharpUtils? _instance; public static FSharpUtils Instance { get { MiscellaneousUtils.Assert(_instance != null); return _instance; } } private MethodInfo _ofSeq; private Type _mapType; public Assembly FSharpCoreAssembly { get; private set; } public MethodCall IsUnion { get; private set; } public MethodCall GetUnionCases { get; private set; } public MethodCall PreComputeUnionTagReader { get; private set; } public MethodCall PreComputeUnionReader { get; private set; } public MethodCall PreComputeUnionConstructor { get; private set; } public Func GetUnionCaseInfoDeclaringType { get; private set; } public Func GetUnionCaseInfoName { get; private set; } public Func GetUnionCaseInfoTag { get; private set; } public MethodCall GetUnionCaseInfoFields { get; private set; } public const string FSharpSetTypeName = "FSharpSet`1"; public const string FSharpListTypeName = "FSharpList`1"; public const string FSharpMapTypeName = "FSharpMap`2"; public static void EnsureInitialized(Assembly fsharpCoreAssembly) { if (_instance == null) { lock (Lock) { if (_instance == null) { _instance = new FSharpUtils(fsharpCoreAssembly); } } } } private static MethodInfo GetMethodWithNonPublicFallback(Type type, string methodName, BindingFlags bindingFlags) { MethodInfo methodInfo = type.GetMethod(methodName, bindingFlags); // if no matching method then attempt to find with nonpublic flag // this is required because in WinApps some methods are private but always using NonPublic breaks medium trust // https://github.com/JamesNK/Newtonsoft.Json/pull/649 // https://github.com/JamesNK/Newtonsoft.Json/issues/821 if (methodInfo == null && (bindingFlags & BindingFlags.NonPublic) != BindingFlags.NonPublic) { methodInfo = type.GetMethod(methodName, bindingFlags | BindingFlags.NonPublic); } return methodInfo!; } private static MethodCall CreateFSharpFuncCall(Type type, string methodName) { MethodInfo innerMethodInfo = GetMethodWithNonPublicFallback(type, methodName, BindingFlags.Public | BindingFlags.Static); MethodInfo invokeFunc = innerMethodInfo.ReturnType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance); MethodCall call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(innerMethodInfo); MethodCall invoke = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(invokeFunc)!; MethodCall createFunction = (target, args) => { object? result = call(target, args); FSharpFunction f = new FSharpFunction(result, invoke); return f; }; return createFunction; } public ObjectConstructor CreateSeq(Type t) { MethodInfo seqType = _ofSeq.MakeGenericMethod(t); return JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(seqType); } public ObjectConstructor CreateMap(Type keyType, Type valueType) { MethodInfo creatorDefinition = typeof(FSharpUtils).GetMethod("BuildMapCreator"); MethodInfo creatorGeneric = creatorDefinition.MakeGenericMethod(keyType, valueType); return (ObjectConstructor)creatorGeneric.Invoke(this, null); } public ObjectConstructor BuildMapCreator() { Type genericMapType = _mapType.MakeGenericType(typeof(TKey), typeof(TValue)); ConstructorInfo ctor = genericMapType.GetConstructor(new[] { typeof(IEnumerable>) }); ObjectConstructor ctorDelegate = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(ctor); ObjectConstructor creator = args => { // convert dictionary KeyValuePairs to Tuples IEnumerable> values = (IEnumerable>)args[0]!; IEnumerable> tupleValues = values.Select(kv => new Tuple(kv.Key, kv.Value)); return ctorDelegate(tupleValues); }; return creator; } } } #endif