You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 06:54:56