Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C语言中多维数组的一般访问#_C#_Arrays_Generics - Fatal编程技术网

C# C语言中多维数组的一般访问#

C# C语言中多维数组的一般访问#,c#,arrays,generics,C#,Arrays,Generics,C#允许创建和填充多维数组,下面是一个简单的示例: public static void Main(String[] args) { var arr = (int[,])CreateArray(new [] {2, 3}, 8); Console.WriteLine("Value: " + arr[0,0]); } // Creates a multidimensional array with the given dimensi

C#允许创建和填充多维数组,下面是一个简单的示例:

    public static void Main(String[] args)
    {
        var arr = (int[,])CreateArray(new [] {2, 3}, 8);
        Console.WriteLine("Value: " + arr[0,0]);
    }

    // Creates a multidimensional array with the given dimensions, and assigns the
    // given x to the first array element
    public static Array CreateArray<T>(int[] dimLengths, T x)
    {
        var arr = Array.CreateInstance(typeof(T), dimLengths);
        var indices = new int[dimLengths.Length];
        for (var i = 0; i < indices.Length; i++)
            indices[i] = 0;
        arr.SetValue(x, indices);  // Does boxing/unboxing
        return arr;
    }
publicstaticvoidmain(字符串[]args)
{
var arr=(int[,])CreateArray(新[]{2,3},8);
控制台写入线(“值:+arr[0,0]);
}
//创建具有给定维度的多维数组,并指定
//给第一个数组元素指定x
公共静态数组CreateArray(int[]dimLength,T x)
{
var arr=Array.CreateInstance(typeof(T),dimLength);
var指数=新整数[dimLength.Length];
对于(var i=0;i

这很有效。但是,由于某些原因,没有Array.SetValue()的通用版本,因此上面的代码执行装箱/取消装箱,这是我想要避免的。我想知道我是否遗漏了什么,或者这是.NET API中的一个遗漏?

我也没有找到任何通用的方法将值设置到数组实例中,因此我想唯一的解决方法是使用不安全的上下文来避免装箱

然而,现在当我想到它时,可能没有通用版本。请参见,当您定义泛型方法
method()…
时,您确实为该方法定义了参数:
…(T[]a)
,其中必须具体说明维度计数,即1。要创建二维参数,可以这样定义它:
…(T[,]a)…
等等


正如您所看到的,根据C#的当前语法,您无法创建一个可以接受任何维度数组的通用方法。

不,您没有遗漏任何内容:
数组
没有设置值而不装箱和取消装箱的选项

对于LINQ,您确实有一个替代方案,但它可能比单个元素的装箱/拆箱慢,因为编译动态lambda将“吃掉”潜在的好处:

public static Array CreateArray<T>(int[] dimLengths, T x) {
    var arr = Array.CreateInstance(typeof(T), dimLengths);

    var p = Expression.Parameter(typeof(object), "arr");
    var ind = new Expression[dimLengths.Length];
    for (var i = 0; i < dimLengths.Length; i++) {
        ind[i] = Expression.Constant(0);
    }
    var v = Expression.Variable(arr.GetType(), "cast");
    var block = Expression.Block(
        new[] {v}
    ,   new Expression[] {
            Expression.Assign(v, Expression.Convert(p, arr.GetType()))
        ,   Expression.Assign(Expression.ArrayAccess(v, ind), Expression.Constant(x))
        ,   Expression.Constant(null, typeof(object))
        }
    );
    Expression.Lambda<Func<object, object>>(block, p).Compile()(arr);
    return arr;
}
公共静态数组CreateArray(int[]dimLength,T x){
var arr=Array.CreateInstance(typeof(T),dimLength);
var p=表达式参数(typeof(object),“arr”);
var ind=新表达式[dimLength.Length];
对于(变量i=0;i
如果您想设置一个循环中的所有元素,可以修改上面的内容,以编译一个具有多个嵌套循环的动态创建的lambda。在这种情况下,您可以改进必须在一系列嵌套循环中执行多个装箱和取消装箱

由于某些原因,没有通用版本的
Array.SetValue()


虽然可以在
数组
类中编写类似于
SetValue
的通用方法,但可能并不可取。非泛型类上的泛型方法会给出错误的编译时类型安全承诺,这是无法保证的,因为编译器不知道
Array
对象的运行时类型。

数组有一个属性。@HansPassant,有问题的数组协方差如何?为什么它不阻止泛型SetValue()方法的存在?所需的运行时类型检查不能绕过,泛型的要点是这些检查是在编译时执行的。泛型管道缺少在运行时执行此操作的基础结构。不需要
for
循环。新数组保证在创建时初始化。因此,
newint[L]
生成一个数组,数组中填充了
default(int)
,即
0
。在编译时,数组的秩是未知的,无法绕过装箱。但我想知道在更常见的情况下会发生什么,C#编译器知道数组的秩和元素类型。所以如果我写代码
int[,]arr=newint[2,3];arr[0,0]=8
,值
8
是否要装箱?我想不是。下次我遇到C#编译器时,会从生成的IL中进行检查;确实存在接受对象和索引数组的非泛型SetValue()方法。为什么不能有一个SetValue(T,Int32[])做同样的事情?注意:我并不是试图创建一个接受未知维度数组的泛型方法,我只希望有一个泛型SetValue()重载。@Shay,我刚才告诉过你为什么。试着创建你自己的方法,看起来你认为必须这样做,你会理解的。我很清楚,我不能编写一个接受未知维度数组的泛型方法。我试图理解的是为什么.NET API没有提供一个通用的SetValue(t,Int32[]),它与已经存在的非通用版本完全对应。换句话说,我试图了解微软不能提供这项服务是否有某些特定的原因?代码生成方法很有趣,如果使用了大量元素,那么它确实是值得的(编译lambda很昂贵,但只发生一次)。正如您所说,LINQ不是一个选项,因为性能。。。