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

C# .NET7游戏开发:无反射按类型名自动调用构造方法(适配Native AOT)

无反射实现Native AOT兼容的资产类型自动映射方案

针对.NET 7 Native AOT环境下无法使用反射的限制,以下是几种无需手动维护庞大switch语句的自动类型映射方案:

方案1:编译时代码生成(Source Generator)

这是最适配Native AOT的方案,完全在编译阶段生成静态映射代码,无运行时开销,彻底避开反射限制。

实现步骤:

  1. 定义标记属性:给所有IAsset实现类添加自定义属性标记类型ID
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public sealed class AssetTypeAttribute : Attribute
{
    public string TypeId { get; }
    public AssetTypeAttribute(string typeId) => TypeId = typeId;
}
  1. 编写Source Generator:创建.NET Standard类库实现ISourceGenerator,扫描所有带标记的IAsset类,自动生成类型映射代码
[Generator]
public class AssetFactoryGenerator : ISourceGenerator
{
    public void Initialize(GeneratorInitializationContext context) { }

    public void Execute(GeneratorExecutionContext context)
    {
        var assetType = context.Compilation.GetTypeByMetadataName("YourNamespace.IAsset");
        if (assetType == null) return;

        // 收集所有符合条件的IAsset实现类
        var assetClasses = context.Compilation.SyntaxTrees
            .SelectMany(tree => tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>())
            .Select(classDecl => context.Compilation.GetSemanticModel(classDecl.SyntaxTree).GetDeclaredSymbol(classDecl) as INamedTypeSymbol)
            .Where(symbol => symbol != null && symbol.ImplementsInterface(assetType) && symbol.GetAttributes().Any(attr => attr.AttributeClass?.Name == "AssetTypeAttribute"));

        // 生成静态工厂类代码
        var codeBuilder = new StringBuilder(@"
namespace YourNamespace;
public static class AssetFactory
{
    private static readonly Dictionary<string, Func<byte[], IAsset>> _factories = new()
    {
");

        foreach (var symbol in assetClasses)
        {
            var typeIdAttr = symbol.GetAttributes().First(attr => attr.AttributeClass?.Name == "AssetTypeAttribute");
            var typeId = typeIdAttr.ConstructorArguments[0].Value.ToString();
            codeBuilder.AppendLine($"        {{ \"{typeId}\", data => new {symbol.Name}(data) }},");
        }

        codeBuilder.Append(@"
    };

    public static IAsset Instantiate(string id, byte[] data)
    {
        if (_factories.TryGetValue(id, out var factory))
            return factory(data);
        throw new ArgumentException($""Unknown asset type: {id}"");
    }
}");

        context.AddSource("AssetFactory.g.cs", codeBuilder.ToString());
    }
}
  1. 使用生成的代码:给IAsset实现类标记属性后,编译时会自动生成AssetFactory,直接调用即可
[AssetType("Player")]
public class Player : IAsset
{
    public Player(byte[] data)
    {
        // 反序列化逻辑
    }
}

// 调用示例
var player = AssetFactory.Instantiate("Player", dataBytes);

方案2:静态构造函数自动注册(无代码生成)

如果不想编写Source Generator,可利用静态构造函数特性,让每个IAsset类自动注册到全局静态字典,Native AOT完全支持这种静态初始化方式。

实现代码:

public static class AssetFactory
{
    public static readonly Dictionary<string, Func<byte[], IAsset>> Factories = new();

    public static IAsset Instantiate(string id, byte[] data)
    {
        if (Factories.TryGetValue(id, out var factory))
            return factory(data);
        throw new ArgumentException($"Unknown asset type: {id}");
    }
}

// 可选基类简化注册逻辑
public abstract class AssetBase : IAsset
{
    protected AssetBase(string typeId, Func<byte[], IAsset> factory)
    {
        AssetFactory.Factories.TryAdd(typeId, factory);
    }
}

// 实现类示例
public class Player : AssetBase
{
    // 静态构造函数自动完成注册
    static Player()
    {
        new Player("Player", data => new Player(data));
    }

    // 仅用于注册的私有构造
    private Player(string typeId, Func<byte[], IAsset> factory) : base(typeId, factory) { }

    // 实际反序列化构造
    public Player(byte[] data)
    {
        // 反序列化逻辑
    }
}

优化补充:ModuleInitializer确保提前加载

用.NET 7+的[ModuleInitializer]特性,在游戏启动时批量触发所有IAsset类的静态构造,避免首次调用Instantiate时的延迟:

public static class AssetInitializer
{
    [ModuleInitializer]
    public static void InitializeAssets()
    {
        // 新增类型只需在这里添加一行
        _ = typeof(Player);
        _ = typeof(Vehicle);
        _ = typeof(Weapon);
    }
}

内容的提问来源于stack exchange,提问作者Ma_rv

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 15:31:58