You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 lines
8.9 KiB

  1. #region License
  2. // Copyright (c) 2007 James Newton-King
  3. //
  4. // Permission is hereby granted, free of charge, to any person
  5. // obtaining a copy of this software and associated documentation
  6. // files (the "Software"), to deal in the Software without
  7. // restriction, including without limitation the rights to use,
  8. // copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following
  11. // conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be
  14. // included in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  18. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23. // OTHER DEALINGS IN THE SOFTWARE.
  24. #endregion
  25. #if !NET20
  26. using System.Threading;
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Linq;
  30. using System.Reflection;
  31. using System.Text;
  32. using Newtonsoft.Json.Serialization;
  33. namespace Newtonsoft.Json.Utilities
  34. {
  35. internal class FSharpFunction
  36. {
  37. private readonly object _instance;
  38. private readonly MethodCall<object, object> _invoker;
  39. public FSharpFunction(object instance, MethodCall<object, object> invoker)
  40. {
  41. _instance = instance;
  42. _invoker = invoker;
  43. }
  44. public object Invoke(params object[] args)
  45. {
  46. object o = _invoker(_instance, args);
  47. return o;
  48. }
  49. }
  50. internal static class FSharpUtils
  51. {
  52. private static readonly object Lock = new object();
  53. private static bool _initialized;
  54. private static MethodInfo _ofSeq;
  55. private static Type _mapType;
  56. public static Assembly FSharpCoreAssembly { get; private set; }
  57. public static MethodCall<object, object> IsUnion { get; private set; }
  58. public static MethodCall<object, object> GetUnionCases { get; private set; }
  59. public static MethodCall<object, object> PreComputeUnionTagReader { get; private set; }
  60. public static MethodCall<object, object> PreComputeUnionReader { get; private set; }
  61. public static MethodCall<object, object> PreComputeUnionConstructor { get; private set; }
  62. public static Func<object, object> GetUnionCaseInfoDeclaringType { get; private set; }
  63. public static Func<object, object> GetUnionCaseInfoName { get; private set; }
  64. public static Func<object, object> GetUnionCaseInfoTag { get; private set; }
  65. public static MethodCall<object, object> GetUnionCaseInfoFields { get; private set; }
  66. public const string FSharpSetTypeName = "FSharpSet`1";
  67. public const string FSharpListTypeName = "FSharpList`1";
  68. public const string FSharpMapTypeName = "FSharpMap`2";
  69. public static void EnsureInitialized(Assembly fsharpCoreAssembly)
  70. {
  71. if (!_initialized)
  72. {
  73. lock (Lock)
  74. {
  75. if (!_initialized)
  76. {
  77. FSharpCoreAssembly = fsharpCoreAssembly;
  78. Type fsharpType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpType");
  79. MethodInfo isUnionMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "IsUnion", BindingFlags.Public | BindingFlags.Static);
  80. IsUnion = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(isUnionMethodInfo);
  81. MethodInfo getUnionCasesMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "GetUnionCases", BindingFlags.Public | BindingFlags.Static);
  82. GetUnionCases = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(getUnionCasesMethodInfo);
  83. Type fsharpValue = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpValue");
  84. PreComputeUnionTagReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionTagReader");
  85. PreComputeUnionReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionReader");
  86. PreComputeUnionConstructor = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionConstructor");
  87. Type unionCaseInfo = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.UnionCaseInfo");
  88. GetUnionCaseInfoName = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("Name"));
  89. GetUnionCaseInfoTag = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("Tag"));
  90. GetUnionCaseInfoDeclaringType = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(unionCaseInfo.GetProperty("DeclaringType"));
  91. GetUnionCaseInfoFields = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(unionCaseInfo.GetMethod("GetFields"));
  92. Type listModule = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.ListModule");
  93. _ofSeq = listModule.GetMethod("OfSeq");
  94. _mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2");
  95. Thread.MemoryBarrier();
  96. _initialized = true;
  97. }
  98. }
  99. }
  100. }
  101. private static MethodInfo GetMethodWithNonPublicFallback(Type type, string methodName, BindingFlags bindingFlags)
  102. {
  103. MethodInfo methodInfo = type.GetMethod(methodName, bindingFlags);
  104. // if no matching method then attempt to find with nonpublic flag
  105. // this is required because in WinApps some methods are private but always using NonPublic breaks medium trust
  106. // https://github.com/JamesNK/Newtonsoft.Json/pull/649
  107. // https://github.com/JamesNK/Newtonsoft.Json/issues/821
  108. if (methodInfo == null && (bindingFlags & BindingFlags.NonPublic) != BindingFlags.NonPublic)
  109. {
  110. methodInfo = type.GetMethod(methodName, bindingFlags | BindingFlags.NonPublic);
  111. }
  112. return methodInfo;
  113. }
  114. private static MethodCall<object, object> CreateFSharpFuncCall(Type type, string methodName)
  115. {
  116. MethodInfo innerMethodInfo = GetMethodWithNonPublicFallback(type, methodName, BindingFlags.Public | BindingFlags.Static);
  117. MethodInfo invokeFunc = innerMethodInfo.ReturnType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance);
  118. MethodCall<object, object> call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(innerMethodInfo);
  119. MethodCall<object, object> invoke = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(invokeFunc);
  120. MethodCall<object, object> createFunction = (target, args) =>
  121. {
  122. object result = call(target, args);
  123. FSharpFunction f = new FSharpFunction(result, invoke);
  124. return f;
  125. };
  126. return createFunction;
  127. }
  128. public static ObjectConstructor<object> CreateSeq(Type t)
  129. {
  130. MethodInfo seqType = _ofSeq.MakeGenericMethod(t);
  131. return JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(seqType);
  132. }
  133. public static ObjectConstructor<object> CreateMap(Type keyType, Type valueType)
  134. {
  135. MethodInfo creatorDefinition = typeof(FSharpUtils).GetMethod("BuildMapCreator");
  136. MethodInfo creatorGeneric = creatorDefinition.MakeGenericMethod(keyType, valueType);
  137. return (ObjectConstructor<object>)creatorGeneric.Invoke(null, null);
  138. }
  139. public static ObjectConstructor<object> BuildMapCreator<TKey, TValue>()
  140. {
  141. Type genericMapType = _mapType.MakeGenericType(typeof(TKey), typeof(TValue));
  142. ConstructorInfo ctor = genericMapType.GetConstructor(new[] { typeof(IEnumerable<Tuple<TKey, TValue>>) });
  143. ObjectConstructor<object> ctorDelegate = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(ctor);
  144. ObjectConstructor<object> creator = args =>
  145. {
  146. // convert dictionary KeyValuePairs to Tuples
  147. IEnumerable<KeyValuePair<TKey, TValue>> values = (IEnumerable<KeyValuePair<TKey, TValue>>)args[0];
  148. IEnumerable<Tuple<TKey, TValue>> tupleValues = values.Select(kv => new Tuple<TKey, TValue>(kv.Key, kv.Value));
  149. return ctorDelegate(tupleValues);
  150. };
  151. return creator;
  152. }
  153. }
  154. }
  155. #endif