简体   繁体   English

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

[英]C# Invoke with out parameter using .net 3.5

I want to invoke a function with two out parameters and bool as return value. 我想调用带有两个out参数的函数,并将bool作为返回值。 Now my problem is I see that those two parameters are changed when I debug, but still they are back to length = 0 (the way they are initialized) when the function returns. 现在我的问题是,我在调试时看到这两个参数已更改,但是当函数返回时,它们仍恢复为length = 0(它们的初始化方式)。

I've seen that there's a great solution for the .net-framework 4, but unfortunaly I have to use the .net-framework 3.5. 我已经看到.net-framework 4有一个很好的解决方案,但是不幸的是,我必须使用.net-framework 3.5。

Here's my code: 这是我的代码:

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

I do not really like "out" keyword, so what about of using a class (Row) that contains information: 我不太喜欢“ 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 });

That modifies the object[] elements. 这将修改object []元素。 C# does not provide syntax to get it to update the arguments of the method, there's an extra level of indirection that you can't bridge with code. C#不提供获取语法来更新方法参数的语法,您无法使用代码来进行额外的间接调用。 It is up to you to copy the references back. 您可以自行复制参考。 Nothing to worry about, you are not actually copying the array content, just the references: 不用担心,您实际上并不是在复制数组内容,而只是复制引用:

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;

Nothing pretty about it of course. 当然没什么好说的。 Do keep in mind that you are certainly doing something very unpretty, you have no guarantee whatsoever that you get the items you expect to get. 请记住,您做的事情肯定很不漂亮,您无法保证获得期望得到的物品。 This code runs at a very unpredictable moment in time, quite disjoint from the code that's running on the UI thread. 这段代码的运行时间非常难以预测,与UI线程上运行的代码完全脱节。 If the user is busy checking items while the worker is running then you get a quite random selection. 如果在工作者运行时用户忙于检查项目,那么您会得到一个相当随机的选择。 A snapshot of the list box state that very quickly turns stale. 列表框状态的快照很快就会过时。

This almost always requires you to disable the list box while the worker is running so you provide a guarantee that the result you compute matches the list. 这几乎总是要求您在工作程序运行时禁用列表框,以便您保证计算的结果与列表匹配。 That in turn means that it is no longer useful to write this code at all, you might as well obtain the list before you start the thread. 反过来,这意味着完全不再需要编写此代码,您还可以启动线程之前获取列表。 Which is the real solution. 真正的解决方案。

I've found a solution that works for me. 我找到了适合我的解决方案。 Still I'm open to different (and better) approaches if you think that this is not a good way to solve this. 如果您认为这不是解决此问题的好方法,我仍然愿意接受其他(更好)的方法。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM