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

时间:2014-02-28 10:12:52

标签: c# .net multithreading .net-3.5 invoke

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

我已经看到.net-framework 4有一个很好的解决方案,但不幸的是我必须使用.net-framework 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);
    }
}

3 个答案:

答案 0 :(得分:2)

我不太喜欢“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(); 
   }
}

答案 1 :(得分:1)

     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线程上运行的代码完全不相交。如果用户在工作人员运行时忙于检查项目,那么您将获得一个非常随机的选择。列表框的快照状态很快就会变为陈旧状态。

这几乎总是要求您在工作程序运行时禁用列表框,以便保证计算结果与列表匹配。这反过来意味着完全编写这个代码已经不再有用了,你也可以在启动线程之前获取列表。哪个是真正的解决方案。

答案 2 :(得分:0)

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

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);
    }
}