如何使 class 在 C# 中用作二维数组?
How do I make a class usable as a 2d array in c#?
代码
Class
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
// whosebug.com/questions/68661235/get-corners-of-a-2d-array
}
}
此代码将失败。
问题
我有一个叫 Foo
的 class。
它的实际值 应该 是类型 int?
的二维数组 - 但是,当我尝试将 Foo 的实例用作 int?[,]
(查看使用部分代码),它失败了(这是预期的)。
那么,如何才能像使用集合一样使用 Foo
的实例,而不必使用 {instance of Foo}.Value
?
我不确定,但我相信这称为包装器。
我试过的
我试图从 IEnumerable
继承 Foo
- 但我以前从未创建过自定义集合类型。因此,在阅读了数小时的教程并盯着 C# 的源代码后,我终于在这里提出了一个关于堆栈溢出的问题。
但是,正如我所说,我 无法实施 IEnumerable
- 这样做可能仍然是我问题的答案。在那种情况下,请告诉我该怎么做。
这可能是我最长的问题了
这是我最终得到的结果:
Class
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);
}
}
实际上您的代码中还有一些错误或问题:
- 一些语法错误(缺少分号)
- 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
// whosebug.com/questions/68661235/get-corners-of-a-2d-array
}
如果您希望能够将 Foo 转换为 int?[],您还需要实现转换操作(如果确实有必要的话)。
代码
Class
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
// whosebug.com/questions/68661235/get-corners-of-a-2d-array
}
}
此代码将失败。
问题
我有一个叫 Foo
的 class。
它的实际值 应该 是类型 int?
的二维数组 - 但是,当我尝试将 Foo 的实例用作 int?[,]
(查看使用部分代码),它失败了(这是预期的)。
那么,如何才能像使用集合一样使用 Foo
的实例,而不必使用 {instance of Foo}.Value
?
我不确定,但我相信这称为包装器。
我试过的
我试图从 IEnumerable
继承 Foo
- 但我以前从未创建过自定义集合类型。因此,在阅读了数小时的教程并盯着 C# 的源代码后,我终于在这里提出了一个关于堆栈溢出的问题。
但是,正如我所说,我 无法实施 IEnumerable
- 这样做可能仍然是我问题的答案。在那种情况下,请告诉我该怎么做。
这可能是我最长的问题了
这是我最终得到的结果:
Class
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);
}
}
实际上您的代码中还有一些错误或问题:
- 一些语法错误(缺少分号)
- 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
// whosebug.com/questions/68661235/get-corners-of-a-2d-array
}
如果您希望能够将 Foo 转换为 int?[],您还需要实现转换操作(如果确实有必要的话)。