如何使一个类在 C# 中用作二维数组?
Posted
技术标签:
【中文标题】如何使一个类在 C# 中用作二维数组?【英文标题】:How do I make a class usable as a 2d array in c#? 【发布时间】:2021-10-12 22:06:11 【问题描述】:代码
类
using System;
using System.Collections.Generic;
// In case you really, really want to know,
// this class is called Ticket in my real code and it's used as a Tambola ticket.
public class Foo
public int?[,] Value get; private set; = new int?[3 , 9]
public Foo () => Value = InternalGenerate()
public static Foo Generate () => new() Value = InternalGenerate() ;
protected static int?[,] InternalGenerate ()
// Generate a random instance of this class.
用法
class Program
static void Main ()
Bar( new() );
static void Bar ( Foo foo )
int width = foo.GetLength(1);
int height = foo.GetLength(0);
int?[] array = foo.Cast<int?>().ToArray(); // convert foo to 1d array.
// get "corners" of foo
int tl = (int) array.First(e => e.HasValue);
int fl = (int) array.Take(width).Last(e => e.HasValue);
int lf = (int) array.Skip(( height - 1 ) * width).First(e => e.HasValue);
int ll = (int) array.Last(e => e.HasValue);
// this code comes from
// ***.com/questions/68661235/get-corners-of-a-2d-array
此代码将失败。
问题
我有一个名为Foo
的课程。
它的实际值 应该 是 int?
类型的二维数组 - 但是,当我尝试使用 Foo 的实例作为 int?[,]
(查看代码的使用部分)时,它失败了(其中预计)。
那么,我如何才能像使用集合一样使用Foo
的实例,而不必使用instance of Foo.Value
?
我不确定,但我相信这被称为包装器。
我尝试过的
我尝试从IEnumerable
继承Foo
- 但我之前从未创建过自定义集合类型。所以,经过几个小时的阅读教程和盯着 C# 的源代码,我终于求助于这里提出了一个关于堆栈溢出的问题。
但是,正如我所说,我无法实现IEnumerable
- 这样做可能仍然是我问题的答案。在这种情况下,请告诉我该怎么做。
这可能是我最长的问题了
【问题讨论】:
从现有实现继承要容易得多,而不必自己实现接口。虽然它不是一个真正的多维集合,但您可以尝试:public class Foo : List<List<int>>
好吧,您可以添加自己的 GetLength
方法和自己的索引器 (docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…) - 很难知道这是否就是您所需要的全部。
@MikalSchachtJensen:通过迭代器实现IEnumerable<T>
非常简单;根据我的经验,从List<T>
派生通常不是一个好主意。 (例如,它经常暴露你不想要的操作。)
您使用 Cast 的用例可以使用来自 Value 的非泛型 Enumerator 进行处理。然而,这不是很有效,使用拳击。因此,请让我们相信一个更好更现实的用例。
含义:扩展// do some stuff with array.
【参考方案1】:
其实你的代码还是有一些错误或者问题的:
一些语法错误(缺少分号) rowCount 和 columnCount 不一定反映“Valye”数组的实际值。public IEnumerator<int?> GetEnumerator () => (IEnumerator<int?>) Value.GetEnumerator();
将引发“InvalidCast”运行时异常。
在下面的代码中,这些问题得到了解决:
public class Foo: IEnumerable<int?>
public int?[,] Value get; private set; = new int?[3, 9];
public int? this[int x, int y]
get => Value[x, y];
set => Value[x, y] = value;
public Foo() => Value = InternalGenerate();
public static Foo Generate() => new() Value = InternalGenerate() ;
protected static int?[,] InternalGenerate()
// Generate a random instance of this class.
return new int?[3, 9]
1,2,3,4,5,6,7,8,9 ,
9,8,null,6,5,4,3,2,1 ,
1,2,3,4,5,6,7,8,9
;
public int GetLength(int dimension) => Value.GetLength(dimension);
public IEnumerator<int?> GetEnumerator()
foreach (var item in Value)
yield return item;
IEnumerator IEnumerable.GetEnumerator()
return Value.GetEnumerator();
然后你可以实例化一个 Foo 类型的变量(不是 int?[,])并根据需要使用它:
static void Bar(Foo foo)
int width = foo.GetLength(1);
int height = foo.GetLength(0);
var array = foo; // convert foo to 1d array.
// get "corners" of foo
int tl = (int)array.First(e => e.HasValue);
int fl = (int)array.Take(width).Last(e => e.HasValue);
int lf = (int)array.Skip((height - 1) * width).First(e => e.HasValue);
int ll = (int)array.Last(e => e.HasValue);
// this code comes from
// ***.com/questions/68661235/get-corners-of-a-2d-array
如果您希望能够将 Foo 转换为 int?[,],您还需要实现转换操作(如果确实有必要的话)。
【讨论】:
【参考方案2】:这是我最终得到的结果:
类
using System;
using System.Collections;
using System.Collections.Generic;
// In case you really, really want to know,
// this class is called Ticket in my real code and it's used as a Tambola ticket.
public class Foo
protected int?[,] Value get; set; = new int?[3 , 9];
public Foo () => Value = InternalGenerate();
public static Foo Generate () => new() Value = InternalGenerate() ;
protected static int?[,] InternalGenerate ()
// Generate a random instance of this class.
public IEnumerator<int?> GetEnumerator () => (IEnumerator<int?>) Value.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator () => Value.GetEnumerator();
public int? this[int r , int c]
get => Value [r , c];
private set => Value [r , c] = value;
public const rowCount = 3;
public const columnCount = 9;
用法
class Program
static void Main ()
Bar( new() );
static void Bar ( Foo foo )
int?[] array = foo.Cast<int?>().ToArray(); // convert foo to 1d array.
//get "corners" of foo
int topLeft = (int) array.First(e => e.HasValue);
int topRight(int) array.Take(columnCount).Last(e => e.HasValue);
int bottomLeft = (int) array.Skip(( rowCount - 1 ) * columnCount).First(e => e.HasValue);
int bottomRight = (int) array.Last(e => e.HasValue);
【讨论】:
以上是关于如何使一个类在 C# 中用作二维数组?的主要内容,如果未能解决你的问题,请参考以下文章