C#如何将泛型接口作为类属性实现同一属性支持多类型值
解决方案
这是非常典型的「同一泛型接口的不同实现需要存入同一个属性/字段」的开发场景,完全不需要推翻现有设计,只要新增一层非泛型基接口即可解决报错。
调整后的完整代码
// 新增非泛型基接口,作为所有答案类型的统一父类型 public interface ISubmittedAnswerAnswer { // 可选:如果需要在不知道具体泛型类型的场景下读写Value,可以声明该属性,不需要可以省略 object Value { get; set; } } // 原有泛型接口继承非泛型基接口 public interface ISubmittedAnswerAnswer<T> : ISubmittedAnswerAnswer { // 用new关键字隐藏父接口的Value,实现强类型访问 new T Value { get; set; } } public abstract class SubmittedAnswerAnswer<T> : ISubmittedAnswerAnswer<T> { public abstract T Value { get; set; } // 显式实现非泛型接口的Value,避免和强类型Value冲突 object ISubmittedAnswerAnswer.Value { get => Value; set => Value = (T)value; } } // 以下实现类完全不需要修改 public class MultipleAnswerSubmittedAnswer : SubmittedAnswerAnswer<int[]> { public override int[] Value { get; set; } } public class SingleStringAnswerSubmittedAnswer : SubmittedAnswerAnswer<string> { public override string Value { get; set; } } // SA类的属性就可以用非泛型接口声明,不再报错 public class SA { public int Id { get; set; } public ISubmittedAnswerAnswer Answer { get; set; } }
常用使用方式
- 已知具体答案类型时,可以做类型转换获取强类型Value,无性能损耗:
var sa = new SA(); sa.Answer = new SingleStringAnswerSubmittedAnswer { Value = "选择题答案" }; if (sa.Answer is SingleStringAnswerSubmittedAnswer strAnswer) { // 直接拿到string类型的Value,不需要额外类型转换 Console.WriteLine(strAnswer.Value.Length); }
- 不需要强类型访问时,直接用非泛型Value即可:
Console.WriteLine(sa.Answer.Value);
额外优化建议
如果你的场景里Value只需要读取不需要修改,可以给泛型接口加out T协变修饰符,支持更灵活的派生类型赋值:
public interface ISubmittedAnswerAnswer<out T> : ISubmittedAnswerAnswer { new T Value { get; } }
内容的提问来源于stack exchange,提问作者Chris Rockwell
相关产品推荐
相关产品推荐

