From e4989425e8f8bbb12c81146b9190426403c1934a Mon Sep 17 00:00:00 2001 From: Alex-Rachel <574809918@qq.com> Date: Mon, 17 Mar 2025 12:01:25 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96Activator.CreateInstance,=20?= =?UTF-8?q?=E5=B7=B2=E7=9F=A5=E7=B1=BB=E5=9E=8B=E4=BC=98=E5=85=88=E4=BD=BF?= =?UTF-8?q?=E7=94=A8new=20=E4=BB=A3=E6=9B=BF=E5=8F=8D=E5=B0=84=EF=BC=8C?= =?UTF-8?q?=E5=85=B6=E6=AC=A1=E4=BD=BF=E7=94=A8EmitHelper=E3=80=82?= =?UTF-8?q?=E8=80=97=E6=97=B6=E5=AF=B9=E6=AF=94=EF=BC=9A=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?new=201=EF=BC=8CEmitHelper=203,=20Activator=2010=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameLogic/Module/UIModule/UIModule.cs | 138 +++++++++---- .../GameLogic/Module/UIModule/UIWidget.cs | 4 +- .../GameLogic/Module/UIModule/UIWindow.cs | 4 +- .../Module/UIModule/WindowAttribute.cs | 5 +- .../MemoryPool/MemoryPool.MemoryCollection.cs | 4 +- .../TEngine/Runtime/Core/ModuleSystem.cs | 2 +- .../Runtime/Core/Utility/EmitHelper.cs | 193 ++++++++++++++++++ .../Runtime/Core/Utility/EmitHelper.cs.meta | 3 + .../ObjectPoolModule/ObjectPoolModule.cs | 2 +- .../ProcedureModule/ProcedureSetting.cs | 2 +- .../TEngine/Runtime/Module/RootModule.cs | 6 +- 11 files changed, 309 insertions(+), 54 deletions(-) create mode 100644 UnityProject/Assets/TEngine/Runtime/Core/Utility/EmitHelper.cs create mode 100644 UnityProject/Assets/TEngine/Runtime/Core/Utility/EmitHelper.cs.meta diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIModule.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIModule.cs index 416f360a..cbdfd2f2 100644 --- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIModule.cs +++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIModule.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using Cysharp.Threading.Tasks; using GameLogic; using TEngine; @@ -8,35 +9,43 @@ using UnityEngine.UI; namespace GameLogic { + /// + /// UI管理模块。 + /// public sealed partial class UIModule : Singleton, IUpdate { - private static Transform _instanceRoot = null; + // 核心字段 + private static Transform _instanceRoot = null; // UI根节点变换组件 + private bool _enableErrorLog = true; // 是否启用错误日志 + private Camera _uiCamera = null; // UI专用摄像机 + private readonly List _uiStack = new List(128); // 窗口堆栈 + private ErrorLogger _errorLogger; // 错误日志记录器 - private bool _enableErrorLog = true; - - private Camera _uiCamera = null; - - private readonly List _uiStack = new List(100); - - public const int LAYER_DEEP = 2000; + // 常量定义 + public const int LAYER_DEEP = 2000; public const int WINDOW_DEEP = 100; public const int WINDOW_HIDE_LAYER = 2; // Ignore Raycast public const int WINDOW_SHOW_LAYER = 5; // UI + // 资源加载接口 public static IUIResourceLoader Resource; /// - /// UI根节点。 + /// UI根节点访问属性 /// public static Transform UIRoot => _instanceRoot; /// - /// UI根节点。 + /// UI摄像机访问属性 /// public Camera UICamera => _uiCamera; - - private ErrorLogger _errorLogger; + /// + /// 模块初始化(自动调用)。 + /// 1. 查找场景中的UIRoot + /// 2. 初始化资源加载器 + /// 3. 配置错误日志系统 + /// protected override void OnInit() { var uiRoot = GameObject.Find("UIRoot"); @@ -84,6 +93,12 @@ namespace GameLogic } } + /// + /// 模块释放(自动调用)。 + /// 1. 清理错误日志系统 + /// 2. 关闭所有窗口 + /// 3. 销毁UI根节点 + /// protected override void OnRelease() { if (_errorLogger != null) @@ -103,7 +118,7 @@ namespace GameLogic /// /// 设置屏幕安全区域(异形屏支持)。 /// - /// 安全区域 + /// 安全区域矩形(基于屏幕像素坐标)。 public static void ApplyScreenSafeRect(Rect safeRect) { CanvasScaler scaler = UIRoot.GetComponentInParent(); @@ -232,9 +247,9 @@ namespace GameLogic /// /// 用户自定义数据。 /// 打开窗口操作句柄。 - public void ShowUIAsync(params System.Object[] userDatas) where T : UIWindow + public void ShowUIAsync(params System.Object[] userDatas) where T : UIWindow , new() { - ShowUIImp(typeof(T), true, userDatas); + ShowUIImp(true, userDatas); } /// @@ -254,9 +269,9 @@ namespace GameLogic /// 窗口类。 /// 用户自定义数据。 /// 打开窗口操作句柄。 - public void ShowUI(params System.Object[] userDatas) where T : UIWindow + public void ShowUI(params System.Object[] userDatas) where T : UIWindow , new() { - ShowUIImp(typeof(T), false, userDatas); + ShowUIImp(false, userDatas); } /// @@ -264,9 +279,9 @@ namespace GameLogic /// /// 用户自定义数据。 /// 打开窗口操作句柄。 - public async UniTask ShowUIAsyncAwait(params System.Object[] userDatas) where T : UIWindow + public async UniTask ShowUIAsyncAwait(params System.Object[] userDatas) where T : UIWindow , new() { - return await ShowUIAwaitImp(typeof(T), true, userDatas) as T; + return await ShowUIAwaitImp(true, userDatas) as T; } /// @@ -284,38 +299,54 @@ namespace GameLogic { string windowName = type.FullName; - // 如果窗口已经存在 - if (IsContains(windowName)) + if (!TryGetWindow(windowName, out UIWindow window, userDatas)) { - UIWindow window = GetWindow(windowName); - Pop(window); //弹出窗口 - Push(window); //重新压入 - window.TryInvoke(OnWindowPrepare, userDatas); - } - else - { - UIWindow window = CreateInstance(type); + window = CreateInstance(type); Push(window); //首次压入 window.InternalLoad(window.AssetName, OnWindowPrepare, isAsync, userDatas).Forget(); } } - private async UniTask ShowUIAwaitImp(Type type, bool isAsync, params System.Object[] userDatas) + private void ShowUIImp(bool isAsync, params System.Object[] userDatas) where T : UIWindow , new() { + Type type = typeof(T); string windowName = type.FullName; - // 如果窗口已经存在 + if (!TryGetWindow(windowName, out UIWindow window, userDatas)) + { + window = CreateInstance(); + Push(window); //首次压入 + window.InternalLoad(window.AssetName, OnWindowPrepare, isAsync, userDatas).Forget(); + } + } + + private bool TryGetWindow(string windowName,out UIWindow window, params System.Object[] userDatas) + { + window = null; if (IsContains(windowName)) { - UIWindow window = GetWindow(windowName); + window = GetWindow(windowName); Pop(window); //弹出窗口 Push(window); //重新压入 window.TryInvoke(OnWindowPrepare, userDatas); - return window; + + return true; + } + return false; + } + + private async UniTask ShowUIAwaitImp(bool isAsync, params System.Object[] userDatas) where T : UIWindow , new() + { + Type type = typeof(T); + string windowName = type.FullName; + + if (TryGetWindow(windowName, out UIWindow window, userDatas)) + { + return window as T; } else { - UIWindow window = CreateInstance(type); + window = CreateInstance(); Push(window); //首次压入 window.InternalLoad(window.AssetName, OnWindowPrepare, isAsync, userDatas).Forget(); float time = 0f; @@ -328,13 +359,14 @@ namespace GameLogic } await UniTask.Yield(); } - return window; + return window as T; } } /// - /// 关闭窗口 + /// 关闭窗口。 /// + /// 窗口类型 public void CloseUI() where T : UIWindow { CloseUI(typeof(T)); @@ -375,7 +407,7 @@ namespace GameLogic window.Visible = false; window.IsHide = true; - window.HideTimerId = ModuleSystem.GetModule().AddTimer((arg) => + window.HideTimerId = GameModule.Timer.AddTimer((arg) => { CloseUI(type); },window.HideTimeToClose); @@ -481,10 +513,32 @@ namespace GameLogic } } } + + private UIWindow CreateInstance() where T : UIWindow , new() + { + Type type = typeof(T); + UIWindow window = new T(); + WindowAttribute attribute = Attribute.GetCustomAttribute(type, typeof(WindowAttribute)) as WindowAttribute; + + if (window == null) + throw new GameFrameworkException($"Window {type.FullName} create instance failed."); + + if (attribute != null) + { + string assetName = string.IsNullOrEmpty(attribute.Location) ? type.Name : attribute.Location; + window.Init(type.FullName, attribute.WindowLayer, attribute.FullScreen, assetName, attribute.FromResources, attribute.HideTimeToClose); + } + else + { + window.Init(type.FullName, (int)UILayer.UI, fullScreen: window.FullScreen, assetName: type.Name, fromResources: false, hideTimeToClose: 10); + } + + return window; + } private UIWindow CreateInstance(Type type) { - UIWindow window = Activator.CreateInstance(type) as UIWindow; + UIWindow window = EmitHelper.CreateInstance(type) as UIWindow; WindowAttribute attribute = Attribute.GetCustomAttribute(type, typeof(WindowAttribute)) as WindowAttribute; if (window == null) @@ -507,7 +561,7 @@ namespace GameLogic /// 异步获取窗口。 /// /// 打开窗口操作句柄。 - public async UniTask GetUIAsyncAwait() where T : UIWindow + public async UniTask GetUIAsyncAwait(CancellationToken cancellationToken) where T : UIWindow { string windowName = typeof(T).FullName; var window = GetWindow(windowName); @@ -536,7 +590,7 @@ namespace GameLogic { break; } - await UniTask.Yield(); + await UniTask.Yield(cancellationToken: cancellationToken); } return ret; } @@ -612,7 +666,9 @@ namespace GameLogic { // 如果已经存在 if (IsContains(window.WindowName)) - throw new System.Exception($"Window {window.WindowName} is exist."); + { + throw new GameFrameworkException($"Window {window.WindowName} is exist."); + } // 获取插入到所属层级的位置 int insertIndex = -1; diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWidget.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWidget.cs index 1c4a5119..a012e168 100644 --- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWidget.cs +++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWidget.cs @@ -55,7 +55,7 @@ namespace GameLogic } /// - /// 窗口可见性 + /// 窗口可见性。 /// public bool Visible { @@ -278,7 +278,7 @@ namespace GameLogic /// 组件被销毁调用。 /// 请勿手动调用! /// - internal void OnDestroyWidget() + protected internal void OnDestroyWidget() { Parent?.SetUpdateDirty(); diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWindow.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWindow.cs index e9558bf4..6c4516c9 100644 --- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWindow.cs +++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/UIWindow.cs @@ -130,7 +130,7 @@ namespace GameLogic } /// - /// 窗口可见性 + /// 窗口可见性。 /// public bool Visible { @@ -174,7 +174,7 @@ namespace GameLogic } /// - /// 窗口交互性 + /// 窗口交互性。 /// private bool Interactable { diff --git a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/WindowAttribute.cs b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/WindowAttribute.cs index 957ce835..a5b70f58 100644 --- a/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/WindowAttribute.cs +++ b/UnityProject/Assets/GameScripts/HotFix/GameLogic/Module/UIModule/WindowAttribute.cs @@ -14,8 +14,11 @@ namespace GameLogic System = 4, } + /// + /// UI窗口属性。 + /// [AttributeUsage(AttributeTargets.Class)] - public class WindowAttribute : Attribute + public class WindowAttribute : Attribute // 用于标记UI窗口,最好完整支持是做成配置表,可以支持货币栏位配置,UI跳转配置等等~ { /// /// 窗口层级 diff --git a/UnityProject/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs b/UnityProject/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs index aba4bcf0..2d222e41 100644 --- a/UnityProject/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs +++ b/UnityProject/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs @@ -77,7 +77,7 @@ namespace TEngine } _addMemoryCount++; - return (IMemory)Activator.CreateInstance(_memoryType); + return (IMemory)EmitHelper.CreateInstance(_memoryType); } public void Release(IMemory memory) @@ -121,7 +121,7 @@ namespace TEngine _addMemoryCount += count; while (count-- > 0) { - _memories.Enqueue((IMemory)Activator.CreateInstance(_memoryType)); + _memories.Enqueue((IMemory)EmitHelper.CreateInstance(_memoryType)); } } } diff --git a/UnityProject/Assets/TEngine/Runtime/Core/ModuleSystem.cs b/UnityProject/Assets/TEngine/Runtime/Core/ModuleSystem.cs index 401590d4..d7eb37e1 100644 --- a/UnityProject/Assets/TEngine/Runtime/Core/ModuleSystem.cs +++ b/UnityProject/Assets/TEngine/Runtime/Core/ModuleSystem.cs @@ -106,7 +106,7 @@ namespace TEngine /// 要创建的游戏框架模块。 private static Module CreateModule(Type moduleType) { - Module module = (Module)Activator.CreateInstance(moduleType); + Module module = (Module)EmitHelper.CreateInstance(moduleType); if (module == null) { throw new GameFrameworkException(Utility.Text.Format("Can not create module '{0}'.", moduleType.FullName)); diff --git a/UnityProject/Assets/TEngine/Runtime/Core/Utility/EmitHelper.cs b/UnityProject/Assets/TEngine/Runtime/Core/Utility/EmitHelper.cs new file mode 100644 index 00000000..bf30026b --- /dev/null +++ b/UnityProject/Assets/TEngine/Runtime/Core/Utility/EmitHelper.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +namespace TEngine +{ + public static class EmitHelper + { + private static readonly Dictionary _defaultCache = new Dictionary(); + + private static readonly Dictionary _argCache = new Dictionary(); + + public static T CreateInstance() where T : new() + { + var type = typeof(T); + + if (!_defaultCache.TryGetValue(type, out var factory)) + { + if (!_defaultCache.TryGetValue(type, out factory)) + { + factory = CreateFactory(); + _defaultCache.TryAdd(type, factory); + } + } + + return ((Func)factory)(); + } + + public static object CreateInstance(Type type) + { + if (!_defaultCache.TryGetValue(type, out var factory)) + { + lock (_defaultCache) + { + if (!_defaultCache.TryGetValue(type, out factory)) + { + var constructor = type.GetConstructor( + BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, + null, Type.EmptyTypes, null); + + if (constructor == null) + { + throw new MissingMethodException($"No parameterless constructor defined for type '{type.FullName}'"); + } + + // 创建动态方法(关键优化点) + var dynamicMethod = new DynamicMethod( + name: $"CreateInstance_{type.FullName}", + returnType: typeof(object), + parameterTypes: Type.EmptyTypes, + owner: typeof(object), + skipVisibility: true); + + // 生成IL指令(核心逻辑) + var il = dynamicMethod.GetILGenerator(); + + // 处理值类型和引用类型的差异 + if (type.IsValueType) + { + il.DeclareLocal(type); + il.Emit(OpCodes.Ldloca_S, 0); + il.Emit(OpCodes.Initobj, type); + il.Emit(OpCodes.Ldloc_0); + il.Emit(OpCodes.Box, type); // 值类型需要装箱 + } + else + { + il.Emit(OpCodes.Newobj, constructor); + } + + il.Emit(OpCodes.Ret); + + factory = dynamicMethod.CreateDelegate(typeof(Func)); + _defaultCache.TryAdd(type, factory); + } + } + } + + return ((Func)factory)(); + } + + private static Func CreateFactory() where T : new() + { + var constructor = typeof(T).GetConstructor( + BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, + null, Type.EmptyTypes, null); + + var dynamicMethod = new DynamicMethod( + name: $"CreateInstance_{typeof(T).FullName}", + returnType: typeof(T), + parameterTypes: Type.EmptyTypes, + owner: typeof(object), // 关键优化:使用object类型模块 + skipVisibility: true); + + var il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Newobj, constructor); + il.Emit(OpCodes.Ret); + + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + } + + + public static object CreateInstance(Type type, params object[] args) + { + if (type == null) throw new ArgumentNullException(nameof(type)); + args ??= Array.Empty(); + + // 预转换参数类型数组 + var argTypes = Array.ConvertAll(args, a => a?.GetType() ?? typeof(object)); + var cacheKey = new CacheKey(type, argTypes); + + if (!_argCache.TryGetValue(cacheKey, out var factory)) + { + if (!_argCache.TryGetValue(cacheKey, out factory)) + { + // 预热动态方法生成 + factory = CreateDynamicFactory(type, argTypes); + _argCache.TryAdd(cacheKey, factory); + + // 预热编译器 + ((Func)factory)(args); + } + } + + return ((Func)factory)(args); + } + + private static Func CreateDynamicFactory(Type type, Type[] argTypes) + { + // 精确匹配构造函数 + var constructor = type.GetConstructor( + BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, + null, argTypes, null) ?? throw new MissingMethodException(type.Name); + + // 创建动态方法 + var dynamicMethod = new DynamicMethod( + name: $"CreateInstance_{type.Name}", + returnType: typeof(object), + parameterTypes: new[] { typeof(object[]) }, + owner: typeof(object), + skipVisibility: true); + + var il = dynamicMethod.GetILGenerator(); + + for (int i = 0; i < argTypes.Length; i++) + { + // 高效参数加载序列(网页9 IL优化) + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldc_I4, i); + il.Emit(OpCodes.Ldelem_Ref); + + // 类型转换合并优化 + if (argTypes[i].IsValueType) + { + il.Emit(OpCodes.Unbox_Any, argTypes[i]); + } + else if (argTypes[i] != typeof(object)) + { + il.Emit(OpCodes.Castclass, argTypes[i]); + } + } + + il.Emit(OpCodes.Newobj, constructor); + + // 统一装箱处理 + if (type.IsValueType) + { + il.Emit(OpCodes.Box, type); + } + + il.Emit(OpCodes.Ret); + + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + } + + private readonly struct CacheKey + { + public readonly Type Type; + + public readonly Type[] ArgTypes; + + public CacheKey(Type type, Type[] argTypes) + { + Type = type; + ArgTypes = argTypes; + } + + public override int GetHashCode() => Type.GetHashCode() ^ ArgTypes.Aggregate(0, (h, t) => h ^ t.GetHashCode()); + } + } +} \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Runtime/Core/Utility/EmitHelper.cs.meta b/UnityProject/Assets/TEngine/Runtime/Core/Utility/EmitHelper.cs.meta new file mode 100644 index 00000000..b5406be6 --- /dev/null +++ b/UnityProject/Assets/TEngine/Runtime/Core/Utility/EmitHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d629990b98cb407dafee703ef18dd2c5 +timeCreated: 1742174169 \ No newline at end of file diff --git a/UnityProject/Assets/TEngine/Runtime/Module/ObjectPoolModule/ObjectPoolModule.cs b/UnityProject/Assets/TEngine/Runtime/Module/ObjectPoolModule/ObjectPoolModule.cs index c1f8aefb..ee69d90b 100644 --- a/UnityProject/Assets/TEngine/Runtime/Module/ObjectPoolModule/ObjectPoolModule.cs +++ b/UnityProject/Assets/TEngine/Runtime/Module/ObjectPoolModule/ObjectPoolModule.cs @@ -1271,7 +1271,7 @@ namespace TEngine Type objectPoolType = typeof(ObjectPool<>).MakeGenericType(objectType); ObjectPoolBase objectPool = - (ObjectPoolBase)Activator.CreateInstance(objectPoolType, name, allowMultiSpawn, autoReleaseInterval, capacity, expireTime, priority); + (ObjectPoolBase)EmitHelper.CreateInstance(objectPoolType, name, allowMultiSpawn, autoReleaseInterval, capacity, expireTime, priority); _objectPools.Add(typeNamePair, objectPool); return objectPool; } diff --git a/UnityProject/Assets/TEngine/Runtime/Module/ProcedureModule/ProcedureSetting.cs b/UnityProject/Assets/TEngine/Runtime/Module/ProcedureModule/ProcedureSetting.cs index 4fb86db0..55442a32 100644 --- a/UnityProject/Assets/TEngine/Runtime/Module/ProcedureModule/ProcedureSetting.cs +++ b/UnityProject/Assets/TEngine/Runtime/Module/ProcedureModule/ProcedureSetting.cs @@ -75,7 +75,7 @@ namespace TEngine return; } - procedures[i] = (ProcedureBase)Activator.CreateInstance(procedureType); + procedures[i] = (ProcedureBase)EmitHelper.CreateInstance(procedureType); if (procedures[i] == null) { Log.Error("Can not create procedure instance '{0}'.", availableProcedureTypeNames[i]); diff --git a/UnityProject/Assets/TEngine/Runtime/Module/RootModule.cs b/UnityProject/Assets/TEngine/Runtime/Module/RootModule.cs index cd73eae0..5c64c57d 100644 --- a/UnityProject/Assets/TEngine/Runtime/Module/RootModule.cs +++ b/UnityProject/Assets/TEngine/Runtime/Module/RootModule.cs @@ -225,7 +225,7 @@ namespace TEngine return; } - Utility.Text.ITextHelper textHelper = (Utility.Text.ITextHelper)Activator.CreateInstance(textHelperType); + Utility.Text.ITextHelper textHelper = (Utility.Text.ITextHelper)EmitHelper.CreateInstance(textHelperType); if (textHelper == null) { Log.Error("Can not create text helper instance '{0}'.", textHelperTypeName); @@ -250,7 +250,7 @@ namespace TEngine } GameFrameworkLog.ILogHelper - logHelper = (GameFrameworkLog.ILogHelper)Activator.CreateInstance(logHelperType); + logHelper = (GameFrameworkLog.ILogHelper)EmitHelper.CreateInstance(logHelperType); if (logHelper == null) { throw new GameFrameworkException(Utility.Text.Format("Can not create log helper instance '{0}'.", @@ -274,7 +274,7 @@ namespace TEngine return; } - Utility.Json.IJsonHelper jsonHelper = (Utility.Json.IJsonHelper)Activator.CreateInstance(jsonHelperType); + Utility.Json.IJsonHelper jsonHelper = (Utility.Json.IJsonHelper)EmitHelper.CreateInstance(jsonHelperType); if (jsonHelper == null) { Log.Error("Can not create JSON helper instance '{0}'.", jsonHelperTypeName);