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

类构造函数初始化paramsGroup字段触发异常的技术求助

构造函数初始化参数列表触发异常,寻求动态参数有序存储方案

我开发了一个将方法归类到类中的应用,用户按下对应按键会触发类内方法,这部分运行正常。但添加名为paramsGroup的List<object>字段(用于存储方法调用所需参数)后,在FileManager类构造函数初始化该列表的位置触发异常。

异常相关代码片段

FileManager类构造函数(异常触发位置)

/// <summary> Performs the Functions related to the File Manager of this Program. </summary>
internal class FileManager : Framework
{
    /// <summary> Creates a new Instance of the FileManager. </summary>
    public FileManager()
    {
        this.ID = 1;
        this.name = Text.LocateByID(Interface.stringsList, "FRAMEWORK_FILE_MANAGER");

        this.paramsGroup = new List<object>() // 构造函数中触发异常的位置
        {
            // Param #0 - Input Path
            Loader.LocateResource<InputPathDialog>(Interface.dialogs).Display(),

            // Param #1 - Output Path
            Loader.LocateResource<OutputPathDialog>(Interface.dialogs).Display(),

            // Param #2 - New Name
            Loader.LocateResource<NewNameDialog>(Interface.dialogs).Display()
        };
        // 剩余代码片段...
    }
}

Loader类的LocateResource方法

/// <summary> Locates a Resource from a Dictionary with the Specific Type. </summary>
/// <param name = "sourceDictionary" > The Dictionary to be Filtered. </param>
/// <returns> The Instance of the Resource obtained. </returns>
public static T LocateResource<T>(Dictionary<string, object> sourceDictionary)
{
    Type resourceType = typeof(T);
    return (T)sourceDictionary[resourceType.Name];
}

参数使用场景(方法重载调用)

this.functionsList = new List<Function>()
{
    // Function A - Display File Properties
    new Function()
    {
        ID = ConsoleKey.A,
        name = Text.LocateByID(Interface.stringsList, "FUNCTION_DISPLAY_FILE_PROPERTIES"),
        process = Task_Manager.CreateTask( () => Archive_Manager.DisplayFileProperties(paramsGroup[0] as string) ) // 从paramsGroup获取第一个元素并转为string
    }
};

前置说明与排查尝试

  • Interface.dialogs字典初始化逻辑:筛选程序集内指定命名空间的类型,通过Activator.CreateInstance创建实例,以类型名为键存入字典。
  • 排查过的尝试:
    • 修改paramsGroup访问修饰符(从protected改为public),问题依旧
    • 将字段类型从List<object>改为object[],结果相同

需求

需要一种有序存储参数的方式,参数可能随用户选择动态变化,方便后续方法调用时随时获取。


异常原因分析与解决方案

1. 构造函数阶段过早调用交互方法

构造函数中直接调用Display()会在类实例化时立即弹出对话框,可能触发线程模型冲突(比如UI/控制台程序的线程限制),或者Interface.dialogs中的实例尚未完成初始化。

解决办法:延迟参数获取
先存储对话框实例,在需要参数时再调用Display():

// 存储对话框实例而非直接调用Display()
private List<object> _dialogInstances;

public FileManager()
{
    this.ID = 1;
    this.name = Text.LocateByID(Interface.stringsList, "FRAMEWORK_FILE_MANAGER");

    _dialogInstances = new List<object>()
    {
        Loader.LocateResource<InputPathDialog>(Interface.dialogs),
        Loader.LocateResource<OutputPathDialog>(Interface.dialogs),
        Loader.LocateResource<NewNameDialog>(Interface.dialogs)
    };
}

// 按需获取参数
private string GetInputPath() => (_dialogInstances[0] as InputPathDialog).Display();

// 方法调用时使用
process = Task_Manager.CreateTask(() => Archive_Manager.DisplayFileProperties(GetInputPath()));

2. 字典键名不匹配导致KeyNotFoundException

Loader.LocateResource用typeof(T).Name作为键,但如果Interface.dialogs的键是完整类型名(含命名空间),会触发键不存在异常。

解决办法:统一键名生成逻辑
如果字典用完整类型名作为键,修改Loader方法:

public static T LocateResource<T>(Dictionary<string, object> sourceDictionary)
{
    Type resourceType = typeof(T);
    return (T)sourceDictionary[resourceType.FullName];
}

3. 类型转换失败引发InvalidCastException

如果Interface.dialogs中的实例不是目标泛型类型,强制转换会触发异常。

解决办法:添加类型校验

public static T LocateResource<T>(Dictionary<string, object> sourceDictionary)
{
    Type resourceType = typeof(T);
    if (sourceDictionary.TryGetValue(resourceType.Name, out var obj))
    {
        if (obj is T tInstance)
        {
            return tInstance;
        }
        throw new InvalidCastException($"对象 {resourceType.Name} 无法转换为 {typeof(T).FullName}");
    }
    throw new KeyNotFoundException($"字典中未找到资源 {resourceType.Name}");
}

4. 更灵活的参数存储方案

如果参数需动态变化,推荐用延迟加载+字典映射替代固定索引列表,可读性与扩展性更强:

// 存储参数获取逻辑,键为参数标识
private Dictionary<string, Func<object>> _parameterProviders = new();

public FileManager()
{
    _parameterProviders.Add("InputPath", () => Loader.LocateResource<InputPathDialog>(Interface.dialogs).Display());
    _parameterProviders.Add("OutputPath", () => Loader.LocateResource<OutputPathDialog>(Interface.dialogs).Display());
    _parameterProviders.Add("NewName", () => Loader.LocateResource<NewNameDialog>(Interface.dialogs).Display());
}

// 调用时直接按标识获取
process = Task_Manager.CreateTask(() => Archive_Manager.DisplayFileProperties(_parameterProviders["InputPath"]() as string));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 06:50:36