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

通过反射访问System.Collections.Immutable及FrozenDictionary时遇类型错误

问题描述

尝试将System.Collections.Immutable作为项目的可选依赖,通过反射实现逻辑:默认使用普通ReadOnlyCollection,若该程序集可用则改用FrozenDictionary(两者都可转换为IReadOnlyDictionary)。

现有反射代码如下:

Assembly assembly = Dependencies.FirstOrDefault(x => x.GetName().Name == "System.Collections.Immutable");
Type staticFrozen = assembly.GetExportedTypes().FirstOrDefault(x => x.Name == "FrozenDictionary" && x.IsAbstract && x.IsSealed);
MethodInfo method = staticFrozen.GetMethods().First(x => x.GetParameters().Length == 2);
IReadOnlyDictionary<char, float> dict = (IReadOnlyDictionary<char, float>)method.MakeGenericMethod(typeof(char), typeof(float)).Invoke(null, new[] { baseDictionary, null } );

代码已包裹在try-catch块中,程序集通过Assembly.Load(byte[])加载成功,但调用ToFrozenDictionary方法时抛出错误:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeLoadException: Could not find method '.ctor' due to a type load error: VTable setup of type System.Collections.Frozen.EmptyFrozenDictionary2[TKey,TValue] failed assembly:data-000002C6933245E0 type:EmptyFrozenDictionary2 member:(null)

不确定问题原因(是否存在嵌入式资源或其他依赖导致故障?),希望获取无需硬编码依赖、未安装该组件时也不会崩溃的访问方案。

解决方案

1. 问题根源

错误源于FrozenDictionary相关类型的依赖链未完整解析:直接通过字节加载System.Collections.Immutable时,它依赖的底层系统组件(如特定版本的System.Runtime、内部辅助类型)未被正确加载,导致内部类型初始化失败。

2. 改进后的反射实现

安全的反射逻辑

逐层做null校验,任何环节失败都降级到ReadOnlyDictionary:

IReadOnlyDictionary<char, float> CreateOptimizedDictionary(Dictionary<char, float> baseDictionary)
{
    try
    {
        // 先查找已加载的程序集
        var immutableAssembly = AppDomain.CurrentDomain.GetAssemblies()
            .FirstOrDefault(a => a.GetName().Name.Equals("System.Collections.Immutable", StringComparison.OrdinalIgnoreCase));
        
        // 尝试从嵌入资源加载(如果项目中嵌入了该dll)
        if (immutableAssembly == null)
        {
            var resourceName = "YourProjectNamespace.System.Collections.Immutable.dll";
            using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
            if (stream == null)
                return new ReadOnlyDictionary<char, float>(baseDictionary);
            
            immutableAssembly = Assembly.Load(stream.ReadAllBytes());
        }

        // 获取FrozenDictionary静态类型(完整命名空间)
        var frozenDictType = immutableAssembly.GetType("System.Collections.Frozen.FrozenDictionary");
        if (frozenDictType == null)
            return new ReadOnlyDictionary<char, float>(baseDictionary);

        // 精准定位ToFrozenDictionary重载(避免参数长度匹配错误)
        var createMethod = frozenDictType.GetMethod(
            "ToFrozenDictionary",
            BindingFlags.Public | BindingFlags.Static,
            new[] { typeof(IEnumerable<KeyValuePair<char, float>>), typeof(IEqualityComparer<char>) });
        
        if (createMethod == null)
            return new ReadOnlyDictionary<char, float>(baseDictionary);

        // 调用方法并返回
        var genericMethod = createMethod.MakeGenericMethod(typeof(char), typeof(float));
        return (IReadOnlyDictionary<char, float>)genericMethod.Invoke(null, new object[] { baseDictionary, null });
    }
    catch (Exception)
    {
        // 任何异常都降级到ReadOnlyDictionary
        return new ReadOnlyDictionary<char, float>(baseDictionary);
    }
}

依赖链处理

如果通过嵌入资源加载程序集:

  • 确保嵌入的System.Collections.Immutable.dll版本与项目的.NET版本兼容
  • 若该程序集依赖System.Memory、System.Runtime.CompilerServices.Unsafe等组件,需一并嵌入并在加载Immutable程序集前优先加载这些依赖

3. 替代方案

NuGet可选依赖配置

在项目文件中设置System.Collections.Immutable为可选依赖,用户安装时可选择是否包含:

<PackageReference Include="System.Collections.Immutable" Version="7.0.0" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />

配合条件编译,在代码中直接调用FrozenDictionary,未安装时自动降级。

条件编译实现

通过预编译指令区分两种逻辑:

#if HAVE_IMMUTABLE
return baseDictionary.ToFrozenDictionary();
#else
return new ReadOnlyDictionary<char, float>(baseDictionary);
#endif

在项目文件中添加条件编译符号:

<PropertyGroup>
  <DefineConstants Condition="Exists('packages\System.Collections.Immutable.7.0.0')">HAVE_IMMUTABLE;$(DefineConstants)</DefineConstants>
</PropertyGroup>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 02:55:33