【问题标题】:C# function that accepts a jagged array of any dimension接受任意维度的交错数组的 C# 函数
【发布时间】:2020-08-29 03:05:19
【问题描述】:

在 C# 中是否可以声明一个接收任意维度的锯齿状数组的函数?现在,如果我在一个接收一维数组的函数中传入一个锯齿状数组,它会给我一个错误:

void func<T>(T[] arr){ 
  return; 
}

double[][] x = new double[10][];
func<double>(x);
// Error: cannot convert from double[][] to double[]

有什么方法可以更改函数签名以使其同时接受一维数组和交错数组?该函数将仅执行适用于锯齿状数组和一维数组的操作。我真的不想使用重载,因为锯齿状数组的维度可能是未知的。

【问题讨论】:

  • 您不需要更改函数签名。您错误地调用了该函数。尝试这样称呼它:func(x)func&lt;double[]&gt;(x)
  • 不能直接把一维数组转成锯齿状数组吗? int[][] jaggedArray = { oneDimArray };
  • 你可以传入一个数组对象:void func&lt;T&gt;(Array arr) 因为数组对象可以表示任何数组类型和任何维度。文档:docs.microsoft.com/en-us/dotnet/api/…
  • @Sweeper 或者让编译器确定正确的类型并直接写func(x)

标签: c# arrays .net visual-studio


【解决方案1】:

要接受任意类型、任意大小和任意维数的数组参数,您可以使用 System 命名空间中的 Array 类。

这是它的样子:

void Function(Array arr)
{
    //Do your stuff with "arr", 
    //you can mostly just treat it like a normal array, looping and so on...
}

如果您想知道特定维度的长度,只需使用Array.GetLength(int Dimension) 函数即可。

如果您还想知道这个数组有多少维,只需使用 Array.Rank 属性。

至于问题,你可以这样做,不会造成任何问题:

double[][] x = new double[10][];
Func<double>(x);

MS 文档:

https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1 https://docs.microsoft.com/en-us/dotnet/api/system.array.rank?view=netcore-3.1

希望这对您有所帮助!

【讨论】:

  • 至于问题,你可以这样做,不会造成任何问题:double[][] x = new double[10][]; Func&lt;double&gt;(x);
  • 我建议将该评论添加到答案本身中,因为它可能是 OP 最有用的方面。
【解决方案2】:

在 C# 中是否可以声明一个接收任意维度的锯齿状数组的函数?

是的,而且您实际上已经拥有了一个。您的解决方案采用任何T[],而T 本身可以是数组类型——这正是锯齿状数组的工作方式。因此,让我们使用您的原始函数(只需将名称更改为更常规的名称,避免与 Func 委托类型混淆):

void ProcessArray<T>(T[] array)
{ 
    // (Method body is irrelevant for now)
}

如果您希望该方法处理double[],则该方法的类型参数(即该方法调用的T 的类型)需要为double。如果希望方法处理double[][],则类型参数需要为double[],以此类推。

您可以通过显式指定类型参数来做到这一点:

double[] simpleArray = new double[10];
ProcessArray<double>(simpleArray);

double[][] jaggedArray = new double[10][];
ProcessArray<double[]>(jaggedArray);

或者,您可以使用通用类型推断让编译器自动确定您想要T 的类型参数:

double[] simpleArray = new double[10];
ProcessArray(simpleArray);

double[][] jaggedArray = new double[10][];
ProcessArray(jaggedArray);

根据我的经验,您可以通常在调用泛型方法时使用类型推断,但也有需要明确指定类型参数的例外情况。

您面临的问题是您提供了double 类型的参数,但提供了double[][] 类型的常规参数。

现在,如果您想在您的方法中处理所有单个元素,例如使用每个“较少锯齿状”数组递归调用您的方法,您可能需要使用反射(例如typeof(T).GetElementType())或Array 类型的成员在执行时获取更多信息。我们不知道您的方法需要完成什么,因此我们目前无法提供比这更具体的建议 - 但希望您可以尝试这两种方法。

【讨论】:

    【解决方案3】:

    &lt;T&gt; 表示任何类型。只要您尊重这种神秘类型&lt;T&gt; 的操作和有效状态,它可以是任何东西。此外,它是从您将方法作为其参数提供的类型推导出来的,因此您只需要在声明它时明确,而在调用它时不需要。

    因此,您进行了更改以接受称为... idk、Transform 的 N 维数组:

    这可能是它的签名:void Transform&lt;T&gt;(T array)。在这种情况下,T 已经是一个数组,如果参数是一个类型为 T 的数组(例如:void f&lt;T&gt;(T[] a),这将是签名,依此类推。

    T 是一个模板,一种在编译时可能构建的类型(有时甚至在运行时)。模板编程的力量是巨大的,并且由于 C# 的编码器优先理念,我们无需为 C++ 教科书流下几滴眼泪就可以体验到它的全部荣耀。

    【讨论】:

    • 这显示了如何创建一个接受any类型的方法,这与接受仅一个数组的方法不同。我相信,汤米的答案是真正解决 OP 问题的答案。 (尽管 OP 的原始代码也是如此,如果他们对无法接受多维数组感到满意的话。)
    • “T 是一个模板”——不,它是一个泛型类型参数。最好不要开始混淆 C++ 模板术语和 C# 泛型术语。
    • OP 的问题比他想象的要简单。这些方法仍然在编译(或运行)时创建,并且每当您调用 f(T a, T b) 时,都会为相应的 sig 生成一个方法。 (T 被任何类型替换,无论是否为数组)。我只是试图向 OP 表明 T 代表 anything... 我没有准确回答他的问题,这是错误的,但我试图补充他对语言和编程的总体了解。
    • 好吧,尽管我很了解 C#,但我并没有真正理解你想说什么,所以我怀疑它对 OP 也没有帮助。我当然不想阻止您尝试提供帮助 - 我只是认为您这次错过了标记(并且对模板的引用肯定没有帮助)。
    • 是该方法的 GENERIC 类型。如果你有F&lt;T&gt;(T[] a),那么如果Tdouble[],参数T[] a 表示T = double[],T[] = double[][]。我正是这个意思。也许如果人们让 OP 先阅读我的答案,然后再因为它不够学术而无法作为硕士论文提出,他可以理解,只是也许,比他的教程、教学和到目前为止,书籍一直试图教他。我想做的就是向 OP 展示带有类型参数的方法没有什么特别之处。
    猜你喜欢
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    • 2013-11-07
    • 1970-01-01
    相关资源
    最近更新 更多