Unity中InvalidCastException问题:泛型类转换错误解决问询
Unity C# 泛型类型转换InvalidCastException解决方案
问题场景
你在Unity项目中通过SetModifiers()返回包含不同泛型参数的ModifierOptionGroup实例列表(Vector2和Vector3类型),但遍历列表时直接将元素强转为ModifierOptionGroup<object>触发了InvalidCastException。
生成列表的代码
public override List<object> SetModifiers() { return new List<object>() { new ModifierOptionGroup<Vector2>( InputType.Dropdown, "Direction", "Choose the direction of the throw", CoreModifiers.GetBaseDirectionModifiers() ), new ModifierOptionGroup<Vector3>( InputType.Dropdown, "Position", "Choose the position", new List<ModifierOption<Vector3>>() { new("Front", "descriptionfront", null, Vector3.forward), new("Back", "descriptionback", null, Vector3.back) } ), }; }
触发错误的遍历代码
foreach (ModifierOptionGroup<object> modifier in modifiers) { GameObject dropdown = Instantiate(dropdownPrefab, panel.transform); Debug.Log("modifier.Label: " + modifier.Label); }
核心原因
C#泛型类默认是不变的,即使Vector2/Vector3继承自object,ModifierOptionGroup<Vector2>和ModifierOptionGroup<object>也属于完全独立的类型,无法直接隐式或显式转换,这就是导致InvalidCastException的根本原因。
解决方案
方案1:定义非泛型基类/接口(推荐)
为ModifierOptionGroup<T>定义一个非泛型的基类或接口,提取所有不需要泛型参数的公共成员(如Label、InputType等),这样可以用非泛型类型统一管理列表,同时保留处理具体泛型类型的能力。
步骤1:定义非泛型接口
public interface IModifierOptionGroup { InputType InputType { get; } string Label { get; } string Description { get; } // 添加其他不需要泛型的公共属性/方法 }
步骤2:让泛型类实现该接口
public class ModifierOptionGroup<T> : IModifierOptionGroup { public InputType InputType { get; } public string Label { get; } public string Description { get; } public List<ModifierOption<T>> Options { get; } // 构造函数及其他逻辑实现 public ModifierOptionGroup(InputType inputType, string label, string description, List<ModifierOption<T>> options) { InputType = inputType; Label = label; Description = description; Options = options; } }
步骤3:修改列表返回类型并遍历
// 修改SetModifiers返回类型 public override List<IModifierOptionGroup> SetModifiers() { return new List<IModifierOptionGroup>() { new ModifierOptionGroup<Vector2>( InputType.Dropdown, "Direction", "Choose the direction of the throw", CoreModifiers.GetBaseDirectionModifiers() ), new ModifierOptionGroup<Vector3>( InputType.Dropdown, "Position", "Choose the position", new List<ModifierOption<Vector3>>() { new("Front", "descriptionfront", null, Vector3.forward), new("Back", "descriptionback", null, Vector3.back) } ), }; } // 遍历代码 foreach (IModifierOptionGroup modifier in modifiers) { GameObject dropdown = Instantiate(dropdownPrefab, panel.transform); Debug.Log("modifier.Label: " + modifier.Label); // 如需处理具体泛型类型,使用模式匹配 if (modifier is ModifierOptionGroup<Vector2> directionGroup) { // 处理Vector2类型的选项组逻辑 } else if (modifier is ModifierOptionGroup<Vector3> positionGroup) { // 处理Vector3类型的选项组逻辑 } }
方案2:使用协变泛型接口(适用于T仅作为输出的场景)
如果ModifierOptionGroup<T>中的泛型参数T仅作为输出(比如只有get属性,没有接收T的方法),可以定义协变接口(使用out关键字),这样允许将IModifierOptionGroup<Vector2>隐式转换为IModifierOptionGroup<object>。
步骤1:定义协变接口
// out关键字标记T为协变类型 public interface IModifierOptionGroup<out T> { InputType InputType { get; } string Label { get; } string Description { get; } IEnumerable<ModifierOption<T>> Options { get; } }
步骤2:修改泛型类实现协变接口
public class ModifierOptionGroup<T> : IModifierOptionGroup<T> { public InputType InputType { get; } public string Label { get; } public string Description { get; } public IEnumerable<ModifierOption<T>> Options { get; } // 构造函数实现 public ModifierOptionGroup(InputType inputType, string label, string description, List<ModifierOption<T>> options) { InputType = inputType; Label = label; Description = description; Options = options; } }
步骤3:修改列表返回类型并遍历
public override List<IModifierOptionGroup<object>> SetModifiers() { return new List<IModifierOptionGroup<object>>() { // 协变允许直接将IModifierOptionGroup<Vector2>转为IModifierOptionGroup<object> new ModifierOptionGroup<Vector2>( InputType.Dropdown, "Direction", "Choose the direction of the throw", CoreModifiers.GetBaseDirectionModifiers() ), new ModifierOptionGroup<Vector3>( InputType.Dropdown, "Position", "Choose the position", new List<ModifierOption<Vector3>>() { new("Front", "descriptionfront", null, Vector3.forward), new("Back", "descriptionback", null, Vector3.back) } ), }; } // 遍历代码 foreach (IModifierOptionGroup<object> modifier in modifiers) { GameObject dropdown = Instantiate(dropdownPrefab, panel.transform); Debug.Log("modifier.Label: " + modifier.Label); }
方案3:保留List
相关产品推荐
相关产品推荐

