.NET 4.6.1中DataGridView列宽属性Setter能否用LINQ实现?
用LINQ实现DataGridView列宽的Setter赋值
嘿,这个问题问得很有意思!答案是可以用LINQ来重构你的Setter逻辑,不过得先给你提个醒:LINQ的设计初衷是用来做数据查询和转换的,不是用来执行修改对象属性这种“副作用”操作的。如果只是想让代码看起来更简洁,那确实有办法,下面给你两种可行的写法:
方法一:用Zip配对列与宽度(最直观)
Zip方法可以把两个序列按位置一一配对,刚好适合我们把列集合和宽度数组对应起来。代码如下:
public int[] MyDataGridViewColWidth { get { return myDataGridView.Columns.Cast<DataGridViewColumn>() .Select(c => c.Width) .ToArray(); } set { // 先做边界校验,避免索引越界或空引用 if (value == null) throw new ArgumentNullException(nameof(value)); if (value.Length != myDataGridView.Columns.Count) throw new ArgumentException("宽度数组的长度必须与DataGridView的列数一致", nameof(value)); // 用Zip配对列和宽度,再通过List.ForEach执行赋值 myDataGridView.Columns.Cast<DataGridViewColumn>() .Zip(value, (column, targetWidth) => new { column, targetWidth }) .ToList() // 必须转成List触发LINQ的执行(延迟加载特性) .ForEach(pair => pair.column.Width = pair.targetWidth); } }
关键说明:
Zip的作用:把DataGridViewColumn的序列和宽度数组按顺序配对,每一组包含一个列和对应的目标宽度。ToList()的必要性:LINQ是延迟执行的,只有当你遍历序列时才会实际执行逻辑。如果不加ToList(),这段代码不会真正去设置列宽,只是定义了一个查询而已。- 边界校验:原来的代码如果传入的数组长度和列数不匹配,会直接抛出
IndexOutOfRangeException。提前加校验可以抛出更清晰的ArgumentException,方便调试。
方法二:用自定义扩展方法(可选)
如果你想让LINQ风格更纯粹,可以自己写一个ForEach扩展方法(不过.NET本身没有内置LINQ的ForEach,因为微软不推荐用LINQ做副作用操作):
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) { if (source == null) throw new ArgumentNullException(nameof(source)); if (action == null) throw new ArgumentNullException(nameof(action)); foreach (var item in source) { action(item); } }
这样Setter里就可以不用转成List了:
set { // 同样先做边界校验... myDataGridView.Columns.Cast<DataGridViewColumn>() .Zip(value, (column, targetWidth) => new { column, targetWidth }) .ForEach(pair => pair.column.Width = pair.targetWidth); }
最后想说的话
虽然用LINQ能实现,但我还是得提醒你:原来的for循环其实可读性更强。因为for循环明确表达了“遍历赋值”的意图,而LINQ写法容易让人误以为是在做数据查询,尤其是不熟悉LINQ延迟加载特性的人,可能会踩坑。所以如果团队里有人对LINQ不太熟悉,保留原来的for循环反而更稳妥。
内容的提问来源于stack exchange,提问作者Markus L
相关产品推荐
相关产品推荐

