现实世界中的例子,其中C#和#x27;输出';参数有用吗?

现实世界中的例子,其中C#和#x27;输出';参数有用吗?,c#,out-parameters,C#,Out Parameters,我正在阅读核心C#编程结构,很难理解out参数修饰符。我通过阅读知道它能做什么,但我试着想一个场景,当我使用它的时候 有人能给我举个真实的例子吗?谢谢。在很多情况下您都会使用它,但最主要的情况是您的方法需要返回多个参数。以int类型上的TryParse方法为例。在这种情况下,不是抛出异常,而是返回一个bool作为成功/失败标志,并返回解析后的int作为out参数。如果要调用int.Parse(…),可能会引发异常 string str = "123456"; int val; if ( !int

我正在阅读核心C#编程结构,很难理解
out
参数修饰符。我通过阅读知道它能做什么,但我试着想一个场景,当我使用它的时候


有人能给我举个真实的例子吗?谢谢。

在很多情况下您都会使用它,但最主要的情况是您的方法需要返回多个参数。以
int
类型上的
TryParse
方法为例。在这种情况下,不是抛出异常,而是返回一个bool作为成功/失败标志,并返回解析后的int作为out参数。如果要调用
int.Parse(…)
,可能会引发异常

string str = "123456";
int val;
if ( !int.TryParse(str,out val) )
{
// do some error handling, notify user, etc.
}

当然,请查看任何
TryParse
方法,例如:

其思想是您实际上需要两条信息:解析操作是否成功(返回值),如果成功,则实际结果是什么(参数
out

用法:

string input = Console.ReadLine();
int value;

// First we check the return value, which is a bool
// indicating success or failure.
if (int.TryParse(input, out value))
{
    // On success, we also use the value that was parsed.
    Console.WriteLine(
        "You entered the number {0}, which is {1}.",
        value,
        value % 2 == 0 ? "even" : "odd"
    );
}
else
{
    // Generally, on failure, the value of an out parameter
    // will simply be the default value for the parameter's
    // type (e.g., default(int) == 0). In this scenario you
    // aren't expected to use it.
    Console.WriteLine(
        "You entered '{0}', which is not a valid integer.",
        input
    );
}
许多开发人员抱怨
out
参数是一种“代码气味”;但在许多情况下,它们可能是迄今为止最合适的选择。一个非常重要的现代例子是多线程代码;通常需要一个
out
参数来允许返回值不够的“原子”操作

例如,
Monitor.TryEnter(object,ref bool)
,它获取一个锁并自动设置一个
bool
,单靠返回值是不可能的,因为锁的获取必然会在返回值分配给
bool
变量之前发生。(是的,从技术上讲,
ref
out
是不一样的;但它们非常接近)


另一个很好的例子是.NET4.0中新增的
System.Collections.Concurrent
命名空间中的集合类可用的一些方法;当您有一个返回多个值的方法时,它们提供类似的线程安全操作,例如
ConcurrentQueue.TryDequeue(out T)
ConcurrentDictionary.TryRemove(TKey,out TValue)
简单。 最“著名”的案例之一是:


输出参数在.NET framework中随处可见。我经常看到的一些用法是方法,它们返回布尔值(指示解析是否有效),实际结果通过输出参数返回。当您需要返回多个值时,使用类也是非常常见的,在这样的示例中,它有点笨手笨脚。有关输出参数的更多信息,请参阅Jon Skeet的文章

或者类似于Dictionary.TryGetValue的东西


当然,我认为这是一个不太好的做法。使用API(如Int32 one)提供的函数来避免Try-Catch是异常。

使用
out
参数的主要动机是允许函数向调用方和框架中提供的所有其他示例返回多个值。我将采用另一种方法来回答您的问题,首先探讨使用
out
参数背后的原因。我不会写出实际的例子,而是描述它们

通常只有一种机制返回值,即函数的返回值。当然,您也可以使用全局(静态)变量或实例变量,但一般来说,这样做既不实用也不安全(原因我在这里不会解释)。在.NET3.5之前,没有真正实用的方法从函数返回多个值。如果
out
ref
修饰符不可用,您将有几个选项:

  • 如果所有值都具有相同的类型,则可以返回一些值的集合。在大多数情况下,这是非常好的,您可以返回数字数组、字符串列表等等。如果所有值都以完全相同的方式关联,则这是完美的。i、 例如,所有数字都是容器中物品的数量,或者列表是聚会上客人的名字。但是,如果返回的值表示不同的数量,该怎么办?如果他们有不同的类型呢?对象列表可以容纳所有对象,但这不是一种非常直观的操作此类数据的方法

  • 对于需要返回不同类型的多个值的情况,唯一实用的选择是创建一个新的类/结构类型来封装所有这些值并返回该类型的实例。这样做可以返回具有直观名称的强类型值,并且可以通过这种方式返回多个值。问题是,为了得到它,您必须使用特定的名称和所有内容定义类型,以便能够返回多个值。如果您只想返回两个值,这两个值足够简单,无法为其创建类型,该怎么办?您还有两个选择:

    • 您可以创建一组泛型类型,以包含不同类型的固定数量的值(如函数式语言中的元组)。但以可重用的方式这样做并没有那么吸引人,因为它当时不是框架的一部分。它可以放在一个库中,但是现在您添加了一个依赖于该库的依赖项,仅仅是为了这些简单类型。(很高兴.NET4.0现在包含了
      Tuple
      类型),但这仍然不能解决这样一个事实,即这些值很简单,这意味着简单任务的复杂性增加了

    • 使用的选项是包含一个
      out
      修饰符,该修饰符允许调用者向变量传递“引用”,以便函数可以将引用的变量设置为返回值的另一种方式。这种返回值的方式在C和C++中也有很多不同的原因,并在相同的原因中起到了一定的作用。
      string value = "";
      
      if (openWith.TryGetValue("tif", out value))
      {
          Console.WriteLine("For key = \"tif\", value = {0}.", value);
      }
      else
      {
          Console.WriteLine("Key = \"tif\" is not found.");
      }
      
      bool Int32.TryParse(String, out Int);
      
      /// <summary>
      /// Example code for how <see cref="int.TryParse(string,out int)"/> might be implemented.
      /// </summary>
      /// <param name="integerString">A string to convert to an integer.</param>
      /// <param name="result">The result of the parse if the operation was successful.</param>
      /// <returns>true if the <paramref name="integerString"/> parameter was successfully 
      /// parsed into the <paramref name="result"/> integer; false otherwise.</returns>
      public bool TryParse(string integerString, out int result)
      {
          try
          {
              result = int.Parse(integerString);
              return true;
          }
          catch (OverflowException)
          {
              // Handle a number that was correctly formatted but 
              // too large to fit into an Int32.
          }
          catch (FormatException)
          {
              // Handle a number that was incorrectly formatted 
              // and so could not be converted to an Int32.
          }
      
          result = 0; // Default.
          return false;
      }
      
      private readonly IDictionary<string,int> mDictionary = new Dictionary<string, int>();
      
      public void IncrementCounter(string counterKey)
      {
          if(mDictionary.ContainsKey(counterKey))
          {
              int existingCount = mDictionary[counterKey];
      
              mDictionary[counterKey] = existingCount + 1;
          }
          else
          {
              mDictionary.Add(counterKey, 1);
          }
      }
      
      public void TryIncrementCounter(string counterKey)
      {
          int existingCount;
          if (mDictionary.TryGetValue(counterKey, out existingCount))
          {
              mDictionary[counterKey] = existingCount + 1;
          }
          else
          {
              mDictionary.Add(counterKey, 1);
          }
      }
      
      //out key word is used in function instead of return. we can use multiple parameters by using out key word
      public void outKeyword(out string Firstname, out string SecondName)
      {
          Firstname = "Muhammad";
          SecondName = "Ismail";
      
      }
      //on button click Event
      protected void btnOutKeyword_Click(object sender, EventArgs e)
      {
          string first, second;
          outKeyword(out first, out second);
          lblOutKeyword.Text = first + "  " + second;
      }