C# 函数结果的可变数目

C# 函数结果的可变数目,c#,C#,我在许多地方有类似于以下的代码: var dbParams = db.ReadParams(memberID, product, GetSubscriptionFields()); Debug.Assert(dbParams.Count == 4); _memberCode = dbParams[0]; _password = dbParams[1]; _userName = dbParams[2]; _reasonCode = dbParams[3]; ReadParams返回字符串数组,

我在许多地方有类似于以下的代码:

var dbParams = db.ReadParams(memberID, product, GetSubscriptionFields());
Debug.Assert(dbParams.Count == 4);

_memberCode = dbParams[0];
_password = dbParams[1];
_userName = dbParams[2];
_reasonCode = dbParams[3];
ReadParams返回字符串数组,字符串数量取决于GetSubscriptionFields函数。我可以在代码中直接使用dbParams[],但我发现为数组中的每个值指定有意义的名称更有用。有没有一种方法可以直接获得所有结果,而不必通过数组

我正在寻找类似于:

db.ReadParams(memberID, product, out _memberCode, out _password, out _userName, out _reasonCode);


当然,它必须是合法的C代码:

为什么不使用常量呢

那么在你的代码中你可以

dbParams[MEMBER_CODE]
dbParams[PASSWORD]
dbParams[USERNAME]
dbParams[REASON_CODE]

在不改变方法工作方式的情况下实现有意义名称的目标。

为什么不使用常量

那么在你的代码中你可以

dbParams[MEMBER_CODE]
dbParams[PASSWORD]
dbParams[USERNAME]
dbParams[REASON_CODE]

在不改变方法工作方式的情况下实现有意义名称的目标。

我认为您的元组思想相当不错。您可以这样定义它:

public class Tuple<T1, T2, T3, T4>
{
    public T1 Field1 { get; set; }
    public T2 Field2 { get; set; }
    public T3 Field3 { get; set; }
    public T4 Field4 { get; set; }
}

您可能需要定义其中的一些属性,包括两个和三个属性。不幸的是,它不能帮助您命名类的属性。至少在C4.0之前,真的没有办法做到这一点,在C4.0之前,您可以使用匿名类型的动态类型。

我认为您的元组思想非常好。您可以这样定义它:

public class Tuple<T1, T2, T3, T4>
{
    public T1 Field1 { get; set; }
    public T2 Field2 { get; set; }
    public T3 Field3 { get; set; }
    public T4 Field4 { get; set; }
}

您可能需要定义其中的一些属性,包括两个和三个属性。不幸的是,它不能帮助您命名类的属性。至少在C4.0之前,真的没有办法做到这一点,在C4.0之前,你可以使用匿名类型的动态类型;因为参数的数量不是固定的,所以没有更好的方法。常规元组的问题是,您仍然在按位置工作-仅使用.Value0而不是[0]。匿名类型不能直接在API中公开

当然,您可以随后在自己的类中用属性包装这些值,然后只进行投影:

 return new Foo {MemberCode = arr[0], ...}
其中,Foo是表示此结果的类,具有命名的类型化属性

或者,您可以将它们放入字典中,但这对调用者的帮助不亚于数组

唯一的另一个选择是一些非常烦人的事情,比如接受一个params数组的动作,你用它来分配每个动作。我将详细介绍最后一个,只是为了好玩-我不建议你这样做:

static void Main()
{
    string name = "";
    int value = 0;
    Foo("whatever",
        x => { name = x; },
        x => { value = int.Parse(x); });    
}
// yucky; wash eyes after reading...
static void Foo(string query, params Action<string>[] actions)
{
    string[] results = Bar(query); // the actual query
    int len = actions.Length < results.Length ? actions.Length : results.Length;
    for (int i = 0; i < len; i++)
    {
        actions[i](results[i]);
    }
}

不是真的;因为参数的数量不是固定的,所以没有更好的方法。常规元组的问题是,您仍然在按位置工作-仅使用.Value0而不是[0]。匿名类型不能直接在API中公开

当然,您可以随后在自己的类中用属性包装这些值,然后只进行投影:

 return new Foo {MemberCode = arr[0], ...}
其中,Foo是表示此结果的类,具有命名的类型化属性

或者,您可以将它们放入字典中,但这对调用者的帮助不亚于数组

唯一的另一个选择是一些非常烦人的事情,比如接受一个params数组的动作,你用它来分配每个动作。我将详细介绍最后一个,只是为了好玩-我不建议你这样做:

static void Main()
{
    string name = "";
    int value = 0;
    Foo("whatever",
        x => { name = x; },
        x => { value = int.Parse(x); });    
}
// yucky; wash eyes after reading...
static void Foo(string query, params Action<string>[] actions)
{
    string[] results = Bar(query); // the actual query
    int len = actions.Length < results.Length ? actions.Length : results.Length;
    for (int i = 0; i < len; i++)
    {
        actions[i](results[i]);
    }
}

您正在用一种高度面向对象的语言编写代码,那么为什么不使用对象呢

Member m = db.ReadParams(memberID, product, GetSubscriptionFields());
在你的代码中你使用

m.memberCode
m.password
m.username
m.reasonCode
当然,您不必公开访问这些值,您可以仅通过setter/getter方法访问它们,并且通过仅使用getter,您可以避免在对象创建后更改它们

当然,对db.ReadParams的不同调用应该返回不同的对象,例如,您可以创建一个抽象基类,并从它的db.ReadParams继承所有可能的结果。因此,您可能必须将db.ReadParams封装到另一个方法中,以找到要创建的正确对象类型:

ReadParamsResult rpr = myDb.ReadParamsAsObject(memberID, product, GetSubscriptionFields());

// Verify that the expected result object has been returned
Debug.Assert(rpr is Member);

// Downcast
Member m = (Member)rpr;

您正在用一种高度面向对象的语言编写代码,那么为什么不使用对象呢

Member m = db.ReadParams(memberID, product, GetSubscriptionFields());
在你的代码中你使用

m.memberCode
m.password
m.username
m.reasonCode
当然,您不必公开访问这些值,您可以仅通过setter/getter方法访问它们,并且通过仅使用getter,您可以避免在对象创建后更改它们

当然,对db.ReadParams的不同调用应该返回不同的对象,例如,您可以创建一个抽象基类,并从它的db.ReadParams继承所有可能的结果。因此,您可能必须将db.ReadParams封装到另一个方法中,以找到要创建的正确对象类型:

ReadParamsResult rpr = myDb.ReadParamsAsObject(memberID, product, GetSubscriptionFields());

// Verify that the expected result object has been returned
Debug.Assert(rpr is Member);

// Downcast
Member m = (Member)rpr;

我也想到了这个。。。我有点喜欢它,但这是我个人的喜好,我知道这绝对不是最干净的主意:

using System.Diagnostics;

public static class ArrayExtractor
{
  public static void Extract<T1>(this object[] array, out T1 value1)
      where T1 : class
  {
    Debug.Assert(array.Length >= 1);
    value1 = array[0] as T1;
  }

  public static void Extract<T1, T2>(this object[] array, out T1 value1, out T2 value2)
      where T1 : class
      where T2 : class
  {
    Debug.Assert(array.Length >= 2);
    value1 = array[0] as T1;
    value2 = array[1] as T2;
  }
}
甚至更好

args.Extract(out fileName, out contents);

其中args当然是一个对象数组。

我还提出了这个。。。我有点喜欢它,但这是我个人的喜好,我知道这绝对不是最干净的主意:

using System.Diagnostics;

public static class ArrayExtractor
{
  public static void Extract<T1>(this object[] array, out T1 value1)
      where T1 : class
  {
    Debug.Assert(array.Length >= 1);
    value1 = array[0] as T1;
  }

  public static void Extract<T1, T2>(this object[] array, out T1 value1, out T2 value2)
      where T1 : class
      where T2 : class
  {
    Debug.Assert(array.Length >= 2);
    value1 = array[0] as T1;
    value2 = array[1] as T2;
  }
}
甚至更好

args.Extract(out fileName, out contents);

其中args当然是一个对象数组。

它基本上仍然是位置数组,即访问
result.Field1与访问结果[0]没有太大区别,假设它们与typedYou是正确的,但您还可以获得一些其他好处。例如,如果您编写了适当的构造函数并将属性限制为只读,那么您至少可以保证返回正确数量的值。它基本上仍然是位置性的,即访问result.Field1与访问result[0]没有太大区别,假设它们与typedYou是正确的,但你还可以得到一些其他好处。例如,如果您编写了适当的构造函数并将属性限制为只读,那么您至少可以保证返回正确数量的值。我喜欢这个想法,它比Mecki的更易于实现。我喜欢这个想法,它比Mecki的更易于实现。非常好的主意,谢谢。现在我选择另一个,因为它实现起来更简单、更快,但我很感激,以后可能会用到它。非常好的主意,谢谢。现在我选择另一个,因为它实现起来更简单、更快,但我很欣赏这一点,以后可能会用到它。