C#使用.net 3.5调用out参数



我想调用一个具有两个out参数和bool作为返回值的函数。现在我的问题是,我看到这两个参数在调试时发生了更改,但当函数返回时,它们仍然返回到length=0(它们的初始化方式)。

我已经看到.net框架4有一个很好的解决方案,但不幸的是,我不得不使用.net框架3.5。

这是我的代码:

public delegate bool GetAllCheckedItemsDelegate(out int[] cTypes, out int[] cFiles);
public bool GetAllCheckedItems(out int[] cTypes , out int[] cFiles ) 
{  
if (ListView.InvokeRequired)
{
cTypes = new int[0];
cFiles = new int[0];
return (bool)ListView.Invoke(new GetAllCheckedItemsDelegate(GetAllCheckedItems), new object[] { cTypes, cFiles });
}
else
{
cTypes = new int[ListView.CheckedItems.Count];
cFiles = new int[ListView.CheckedItems.Count];
for (int i = 0; i < ListView.CheckedItems.Count; i++)
{
// ......code......
}
return (ListView.CheckedItems.Count > 0);
}
}

我真的不喜欢"out"关键字,那么使用一个包含信息的类(Row)怎么样:

using SCG = System.Collections.Generic;
using System.Linq;
public class Row {
public int CheckedType { get; set; }
public int CheckedFile { get; set; }
}
...
public delegate SCG.IEnumerable<Row> GetAllCheckedItemsDelegate();
public bool GetAllCheckedItems() {  
if (ListView.InvokeRequired) {
var rows = ListView.Invoke(new GetAllCheckedItemsDelegate(GetAllCheckedItems)
, new object[] {});
return rows.Count() > 0;
} else {
var rows = new SCG.List<Row>();
for (int i = 0; i < ListView.CheckedItems.Count; i++) {
// create and set row 
var row = new Row { CheckedType = x, CheckedFile = y };
...
rows.Add(row);
}
return rows.AsReadOnly(); 
}
}
return (bool)ListView.Invoke(..., new object[] { cTypes, cFiles });

修改object[]元素。C#没有提供语法来更新方法的参数,有一个额外的间接级别,你无法用代码桥接。由您将参考资料复制回来。无需担心,您实际上并没有复制数组内容,只是复制引用:

var args = new object[] { null, null };
var dlg = new GetAllCheckedItemsDelegate(GetAllCheckedItems);
var retval = (bool)ListView.Invoke(dlg, args);
cTypes = (int[])args[0];
cFiles = (int[])args[1];
return retval;

当然没什么好看的。请记住,你肯定在做一些非常不体面的事情,你不能保证你能得到你想要的东西。这段代码运行在一个非常不可预测的时刻,与UI线程上运行的代码完全脱节。如果用户在工作程序运行时忙于检查项目,则会得到一个非常随机的选择。列表框状态的快照,该状态很快就会过时。

这几乎总是要求您在工作程序运行时禁用列表框,以便确保您计算的结果与列表匹配。这反过来意味着编写此代码不再有用,您还可以在启动线程之前获得列表。这才是真正的解决方案。

我找到了一个适合我的解决方案。如果你认为这不是解决这个问题的好方法,我仍然愿意采用不同的(更好的)方法。

public delegate bool BoolDelegate();    
public bool GetAllCheckedItems(out int[] cTypes , out int[] cFiles ) 
{
if (ListView.InvokeRequired)
{
int[] cTypesHelpVar = new int[0];
int[] cFilesHelpVar = new int[0];
bool ret = (bool)ListView.Invoke((BoolDelegate) (() => GetAllCheckedItems(out cTypesHelpVar, out cFilesHelpVar)));
cTypes = cTypesHelpVar;
cFiles = cFilesHelpVar;
return ret;
}
else
{
cTypes = new int[ListView.CheckedItems.Count];
cFiles = new int[ListView.CheckedItems.Count];
for (int i = 0; i < ListView.CheckedItems.Count; i++)
{
//.... code ....
}
return (ListView.CheckedItems.Count > 0);
}
}

最新更新