"推"入C#数组的最佳方式

phu*_*der 3 c# arrays push

美好的一天

所以我知道这是一个相当广泛讨论的问题,但我似乎无法找到明确的答案.我知道你可以做我要求使用List的东西,但这不会解决我的问题.

我在初学者C#上教课.我有PHP和Java脚本背景,因此倾向于考虑这些语言.

我一直在寻找向学生展示如何动态添加元素的最佳方式.我们不能使用列表,因为这些不是我目前教授的教学大纲的一部分(尽管它们确实会在以后的版本中出现)本学期).

因此,我正在寻找执行Java array.push(newValue)类型场景的最简单方法,这种场景对新手编程人员来说是可以理解的,而不会教他们不好的做法.

到目前为止,我一直在解决这个问题:

for (int i = 0; i < myArray.Length; i++)
{
   if(myArray[i] == null)
   {
       myArray[i] = newValue;
       break;
   }
}
Run Code Online (Sandbox Code Playgroud)

我只是需要知道这是否是一种可接受的方法,如果我教他们任何不良做法,或者是否有更好/更简单的方法来实现我的目标.

编辑问题的关键是元素需要添加到数组中的第一个空槽中,就像Java推送功能所做的那样.

任何建议将不胜感激.

jmc*_*ney 12

array.push就像List<T>.Add..NET数组是固定大小的,因此您无法实际添加新元素.您所能做的就是创建一个比原始元素大一个元素的新数组,然后设置最后一个元素,例如

Array.Resize(ref myArray, myArray.Length + 1);
myArray[myArray.GetUpperBound(0)] = newValue;
Run Code Online (Sandbox Code Playgroud)

编辑:

鉴于对此问题的编辑,我不确定这个答案是否真的适用:

问题的关键在于元素需要被添加到数组中的第一个空槽中,这就是Java推送功能所能做到的.

我提供的代码有效地附加了一个元素.如果目的是设置第一个空元素,那么你可以这样做:

int index = Array.IndexOf(myArray, null);

if (index != -1)
{
    myArray[index] = newValue;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

这是一个扩展方法,它封装了该逻辑并返回放置值的索引,如果没有空元素则返回-1.请注意,此方法也适用于值类型,将具有该类型的默认值的元素视为空.

public static class ArrayExtensions
{
    public static int Push<T>(this T[] source, T value)
    {
        var index = Array.IndexOf(source, default(T));

        if (index != -1)
        {
            source[index] = value;
        }

        return index;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这可行,但我不确定学生会喜欢。:) (3认同)
  • 请注意,这仅在数组类型为引用类型或可空值类型时才有效.它不适用于标准值类型,因为它们不能为"null". (3认同)

Mon*_*nno 6

还有另一种方法可以做到这一点,它非常适合扩展类。

public static void Push<T>(ref T[] table, object value)
{
    Array.Resize(ref table, table.Length + 1);
    table.SetValue(value, table.Length - 1);
}
Run Code Online (Sandbox Code Playgroud)

这里发生的事情是,我们正在调整大小,然后为Array.Resize(...)方法创建的新元素设置值。

这是带有示例用法的片段


Mic*_*zyn 5

如前所述,List提供了以干净的方式添加元素的功能,要对数组执行相同的操作,您必须调整它们的大小以容纳额外的元素,请参阅下面的代码:

int[] arr = new int[2];
arr[0] = 1;
arr[1] = 2;
//without this line we'd get a exception
Array.Resize(ref arr, 3);
arr[2] = 3;
Run Code Online (Sandbox Code Playgroud)

关于循环的想法:

当数组初始化时,数组的元素被设置为其默认值。因此,如果您想在保存引用类型(具有默认值null)的数组中填充“空白”,那么您的方法会很好。

但它不适用于值类型,因为它们是用0!


Fly*_*g57 5

你的问题有点离题。特别是,您说“需要将元素添加到数组中的第一个空槽中,说谎(原文如此) Java 推送函数可以做到。”

  1. Java 的 Array 没有推送操作 - JavaScript 有。Java和JavaScript是两个非常不同的语言
  2. JavaScript 的推送功能与您描述的不一样。当您将一个值“推送”到 JavaScript 数组中时,该数组会扩展一个元素,并为该新元素分配推送的值,请参阅:Mozilla 的 Array.prototype.push 函数文档

动词“推送”在我所知道的除 JavaScript 之外的任何语言中都不能与数组一起使用。我怀疑它只存在于 JavaScript 中,因为它可能存在(因为 JavaScript 是一种完全动态的语言)。我很确定它不是故意设计的。

C# 中 JavaScript 风格的 Push 操作可以用这种有点低效的方式编写:

int [] myArray = new int [] {1, 2, 3, 4};
var tempList = myArray.ToList();
tempList.Add(5);
myArray = tempList.ToArray();   //equiv: myArray.Push(5);
Run Code Online (Sandbox Code Playgroud)

“推送”用于某些类型的容器,特别是堆栈、队列和双端队列(它们有两次推送 - 一次从前面,一次从后面)。我敦促您不要在对数组的解释中将Push作为动词包含在内。它不会增加 CS 学生的词汇量。

在 C# 中,与大多数传统过程语言一样,数组是单一类型元素的集合,包含在固定长度的连续内存块中。分配数组时,会为每个数组元素分配空间(并且,在 C# 中,这些元素被初始化为类型的默认值,引用类型为null)。

在 C# 中,引用类型的数组用对象引用填充;值类型的数组填充有该值类型的实例。因此,4 个字符串的数组与应用程序类的 4 个实例的数组使用相同的内存(因为它们都是引用类型)。但是,4 个 DateTime 实例的数组明显长于 4 个短整数的数组。

在 C# 中,数组的实例是 System.Array(一种引用类型)的实例。数组有一些属性和方法(比如Length属性)。否则,您对数组无能为力:您可以使用数组index从(或向)单个元素读取(或写入)。T 类型的数组也实现了IEnumerable<T>,因此您可以遍历数组的元素。

数组是可变的(数组中的值可以写入),但它们有固定的长度——它们不能被扩展或缩短。它们是有序的,并且不能重新排列(除非手动调整值)。

C# 数组是协变的。如果您问 C# 语言设计人员,这将是他们最后悔的功能。这是破坏 C# 类型安全的少数方法之一。考虑以下代码(假设 Cat 和 Dog 类继承自 Animal):

Cat[] myCats = new Cat[]{myCat, yourCat, theirCat};
Animal[] animals = (Animal[]) myCats;     //legal but dangerous
animals[1] = new Dog();                   //heading off the cliff
myCats[1].Speak();                        //Woof!
Run Code Online (Sandbox Code Playgroud)

该“功能”是 .NET Framework 初始版本中缺乏泛型类型和显式协变/逆变以及复制 Java“功能”的冲动的结果。

数组确实出现在许多核心 .NET API 中(例如 System.Reflection)。它们再次出现,因为初始版本不支持泛型集合。

在一般情况下,一个有经验的C#程序员也不会在他的应用程序中使用的许多阵列,宁愿使用更强大的集合,例如List<T>Dictionary<TKey, TValue>HashSet<T>和朋友。特别是,该程序员倾向于使用IEnumerable<T>所有集合都实现的接口来传递集合。IEnumerable<T>用作参数和返回类型(在可能且符合逻辑的情况下)的最大优点是通过IEnumerable<T>引用访问的集合是不可变的。这有点像const在 C++ 中正确使用。

在每个人都掌握了基础知识之后,您可能会考虑添加到有关数组的讲座中的一件事是新Span<T>类型。Span 可能会使 C# 数组变得有用。

最后,LINQ(语言集成查询)推出了很多的功能集合(通过添加扩展方法IEnumerable<T>)。确保你的学生没有using System.Linq;在他们的代码顶部有一个语句 - 将 LINQ 混合到一个关于数组的初学者课程中会让他或她感到困惑。

BTW:你教的是什么课?在什么水平?