Unity中如何动态传参给BinaryWriter.Write重载函数?
Unity中BinaryWriter自动匹配Write重载的实现方案
首先说你遇到的dynamic报错问题:Unity默认编译环境未包含Microsoft.CSharp.RuntimeBinder相关程序集,而且IL2CPP编译对dynamic支持有限,所以这种方式在Unity里基本走不通,得换其他方案。
下面是几种不用逐个判断类型的实现方式:
方案1:泛型委托缓存(推荐,性能优)
提前为常用类型注册对应的Write委托,初始化时缓存起来,后续调用直接取用,比每次switch判断效率更高:
using System; using System.IO; using System.Collections.Generic; public class PacketWriter { private static readonly Dictionary<Type, Action<BinaryWriter, object>> _writeActions = new Dictionary<Type, Action<BinaryWriter, object>>(); static PacketWriter() { // 注册常用类型的Write逻辑 RegisterWriteAction<int>((writer, val) => writer.Write(val)); RegisterWriteAction<float>((writer, val) => writer.Write(val)); RegisterWriteAction<string>((writer, val) => writer.Write(val)); RegisterWriteAction<bool>((writer, val) => writer.Write(val)); RegisterWriteAction<long>((writer, val) => writer.Write(val)); RegisterWriteAction<byte[]>((writer, val) => writer.Write(val)); // 按需添加其他类型 } private static void RegisterWriteAction<T>(Action<BinaryWriter, T> action) { _writeActions[typeof(T)] = (writer, obj) => action(writer, (T)obj); } public static byte[] CreatePacket(params object[] data) { using (var ms = new MemoryStream()) using (var writer = new BinaryWriter(ms)) { foreach (var item in data) { if (item == null) throw new ArgumentNullException(nameof(item), "不允许写入null值"); var type = item.GetType(); if (_writeActions.TryGetValue(type, out var writeAction)) { writeAction(writer, item); } else { throw new NotSupportedException($"未支持类型:{type.Name}"); } } return ms.ToArray(); } } }
方案2:反射自动匹配Write重载
通过反射遍历BinaryWriter的所有单参数Write重载,缓存对应的MethodInfo,运行时直接调用:
using System; using System.IO; using System.Collections.Generic; using System.Reflection; using System.Linq; public class PacketWriter { private static readonly Dictionary<Type, MethodInfo> _writeMethods = new Dictionary<Type, MethodInfo>(); static PacketWriter() { // 筛选所有单参数的Write重载 var writeMethods = typeof(BinaryWriter).GetMethods(BindingFlags.Public | BindingFlags.Instance) .Where(m => m.Name == "Write" && m.GetParameters().Length == 1); foreach (var method in writeMethods) { var paramType = method.GetParameters()[0].ParameterType; _writeMethods[paramType] = method; } } public static byte[] CreatePacket(params object[] data) { using (var ms = new MemoryStream()) using (var writer = new BinaryWriter(ms)) { foreach (var item in data) { if (item == null) throw new ArgumentNullException(nameof(item)); var type = item.GetType(); if (_writeMethods.TryGetValue(type, out var method)) { method.Invoke(writer, new object[] { item }); } else { throw new NotSupportedException($"BinaryWriter无{type.Name}类型的Write重载"); } } return ms.ToArray(); } } }
这种方式不用手动注册类型,但性能比委托缓存略差,不过Unity多数场景下完全够用。
方案3:泛型重载(编译时匹配,性能最优)
如果调用CreatePacket时能明确知道参数类型,可以写对应参数个数的泛型重载,编译时直接绑定正确的Write方法:
using System.IO; public class PacketWriter { public static byte[] CreatePacket<T>(T val) { using (var ms = new MemoryStream()) using (var writer = new BinaryWriter(ms)) { writer.Write(val); return ms.ToArray(); } } public static byte[] CreatePacket<T1, T2>(T1 val1, T2 val2) { using (var ms = new MemoryStream()) using (var writer = new BinaryWriter(ms)) { writer.Write(val1); writer.Write(val2); return ms.ToArray(); } } // 按需扩展到3个、4个参数的重载... }
这种方式没有运行时开销,但需要提前定义好参数个数的重载,灵活性稍弱。
内容的提问来源于stack exchange,提问作者Bruno
相关产品推荐
相关产品推荐

