如何将不同泛型实现的Worksheet实例存入同一枚举集合?
解决方案
问题的核心是C#泛型默认不支持协变转换,因此Worksheet<WorksheetItem1>无法直接转为Worksheet<IWorksheetItem>。以下是两种可行的实现方案:
方案一:定义非泛型基接口
创建一个非泛型的IWorksheet接口,封装你在GetSpreadSheet中需要访问的公共成员,让泛型Worksheet<T>实现该接口,以此统一所有Worksheet实例的类型。
代码实现
// 非泛型接口,统一公共操作 public interface IWorksheet { string Name { get; set; } Type ItemType { get; } // 可选:若需要以非泛型形式访问Items,添加此属性 IEnumerable<IWorksheetItem> Items { get; } } // 修改泛型Worksheet类实现IWorksheet public class Worksheet<T> : IWorksheet where T : IWorksheetItem { public string Name { get; set; } public IEnumerable<T> Items { get; set; } public Type ItemType => typeof(T); // 显式实现非泛型Items属性,完成类型转换 IEnumerable<IWorksheetItem> IWorksheet.Items => Items; } // 调整GetSpreadSheet方法参数类型 public byte[] GetSpreadSheet(IEnumerable<IWorksheet> worksheets) { foreach (var worksheet in worksheets) { // 反射获取并筛选DateTime相关属性 var properties = worksheet.ItemType.GetProperties(); foreach (var prop in properties) { if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(DateTime?)) { // 此处添加你的DateTime属性处理逻辑 Console.WriteLine($"找到DateTime类型属性:{prop.Name}"); } } } // 后续生成SpreadSheet逻辑 return new byte[0]; } // 使用方式 var worksheets = new List<IWorksheet>(); worksheets.Add(worksheet1); worksheets.Add(worksheet2); worksheets.Add(worksheet3); var result = GetSpreadSheet(worksheets);
方案二:利用泛型协变
如果不需要非泛型接口,可以定义一个协变泛型接口(用out关键字标记),因为你的场景中T仅作为输出(如Items是只读的IEnumerable<T>),符合协变的使用条件。
代码实现
// 协变泛型接口,out关键字标记T为输出类型 public interface IWorksheet<out T> where T : IWorksheetItem { string Name { get; set; } IEnumerable<T> Items { get; } Type ItemType { get; } } // 修改Worksheet类实现协变接口 public class Worksheet<T> : IWorksheet<T> where T : IWorksheetItem { public string Name { get; set; } public IEnumerable<T> Items { get; set; } public Type ItemType => typeof(T); } // 调整GetSpreadSheet方法参数 public byte[] GetSpreadSheet(IEnumerable<IWorksheet<IWorksheetItem>> worksheets) { foreach (var worksheet in worksheets) { var properties = worksheet.ItemType.GetProperties(); foreach (var prop in properties) { if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(DateTime?)) { // 处理DateTime属性逻辑 } } } return new byte[0]; } // 使用方式:协变支持直接转换 var worksheets = new List<IWorksheet<IWorksheetItem>>(); worksheets.Add(worksheet1); worksheets.Add(worksheet2); worksheets.Add(worksheet3); var result = GetSpreadSheet(worksheets);
方案对比
- 方案一:灵活性更强,适合需要在非泛型场景下扩展Worksheet功能的情况,即使后续添加输入型成员(如
AddItem(T item))也不受影响。 - 方案二:代码更简洁,无需额外实现非泛型属性,但仅适用于
T仅作为输出的场景(若有接受T作为参数的方法,协变会失效)。
内容的提问来源于stack exchange,提问作者Jason Butera
相关产品推荐
相关产品推荐

