如何实现支持任意数量泛型参数的C# JSGridVM类?
实现支持任意多不同类型JSTable的JSGridVM方案
先直接回答你的第一个问题:C#里的Func<>系列委托确实是靠多组泛型参数重载实现的。它并没有什么“黑科技”支持无限制泛型参数,只是预定义了从0个输入参数到16个输入参数的重载版本,覆盖绝大多数常见场景。
回到你的核心需求:要让JSGridVM能容纳任意数量、任意RowType的JSTable<RowType>实例。其实你不需要把所有RowType都塞进JSGridVM的泛型参数里(而且C#本身也不支持可变数量的泛型参数),换个思路就能轻松解决。
最优解决方案:非泛型接口+非泛型JSGridVM
这个方案简单、类型安全,还能完美满足你“任意数量JSTable”的需求:
1. 定义非泛型接口IJSTable
先创建一个非泛型接口,用来统一所有JSTable<RowType>的公共非泛型成员:
public interface IJSTable { bool AllowEditingRows { get; set; } bool AllowDeletingRows { get; set; } string UpdateURL { get; set; } string DeleteURL { get; set; } List<JSGridColumn> Columns { get; set; } }
2. 让JSTable<RowType>实现这个接口
修改你的JSTable类,继承IJSTable:
public class JSTable<RowType> : IJSTable { public JSTable() { } public JSTable(List<RowType> rows, List<JSGridColumn> columns, bool allowEditingRows, bool allowDeletingRows, string updateURL, string deleteURL) { Rows = rows; Columns = columns; AllowEditingRows = allowEditingRows; AllowDeletingRows = allowDeletingRows; UpdateURL = updateURL; DeleteURL = deleteURL; } public List<RowType> Rows { get; set; } public List<JSGridColumn> Columns { get; set; } public bool AllowEditingRows { get; set; } public bool AllowDeletingRows { get; set; } public string UpdateURL { get; set; } public string DeleteURL { get; set; } }
3. 实现JSGridVM
现在JSGridVM不需要任何泛型参数,直接持有List<IJSTable>,还可以加个便捷的AddTable方法:
public class JSGridVM { public List<IJSTable> Tables { get; set; } = new List<IJSTable>(); // 便捷方法,自动推导RowType public void AddTable<RowType>(JSTable<RowType> table) { Tables.Add(table); } }
使用示例
这样你想加多少个不同类型的JSTable都可以:
// 创建不同RowType的表格 var userTable = new JSTable<User>(userRows, userColumns, true, true, "/api/users/update", "/api/users/delete"); var orderTable = new JSTable<Order>(orderRows, orderColumns, false, true, "/api/orders/update", "/api/orders/delete"); var productTable = new JSTable<Product>(productRows, productColumns, true, false, "/api/products/update", "/api/products/delete"); // 初始化JSGridVM并添加所有表格 var jsGridVM = new JSGridVM(); jsGridVM.AddTable(userTable); jsGridVM.AddTable(orderTable); jsGridVM.AddTable(productTable);
如果你非要JSGridVM<SomeClass1, SomeClass2>的声明方式
如果确实想接近你期望的泛型声明语法,只能像Func<>那样预定义重载,但这本质上还是有限制的,而且对你的场景来说没什么实际价值。举个例子:
// 基础非泛型类 public class JSGridVM { public List<IJSTable> Tables { get; set; } = new List<IJSTable>(); } // 支持1个泛型参数的版本 public class JSGridVM<T1> : JSGridVM { public void AddTable(JSTable<T1> table) => Tables.Add(table); } // 支持2个泛型参数的版本 public class JSGridVM<T1, T2> : JSGridVM<T1> { public new void AddTable(JSTable<T2> table) => Tables.Add(table); } // 继续扩展到T3、T4……最多到你愿意写的数量
但这种方式需要你预先写好所有可能的泛型参数数量的重载,和Func<>一样最多覆盖有限数量,而且JSGridVM本身并不需要知道这些RowType的具体类型,所以完全没必要这么做。
总结一下
Func<>确实是靠多组泛型参数重载实现的,没有真正的“无限制”泛型参数;- 对你的场景来说,非泛型接口+非泛型JSGridVM是最优解,简单、灵活,能容纳任意数量的不同类型
JSTable; - 泛型声明的方式只是语法糖,无法实现真正的无限制,反而增加不必要的复杂度。
内容的提问来源于stack exchange,提问作者Tyler Youngs
相关产品推荐
相关产品推荐

