【问题标题】:Create a C# method to generate auto increment Id创建一个 C# 方法来生成自动递增 Id
【发布时间】:2019-01-09 12:33:10
【问题描述】:

我是编程新手,我徒劳地尝试创建一个返回自动递增 id 的函数,但是代码不起作用,即使我不明白它是什么,我也确信缺少一些东西. 这里的代码,它的目的是创建一个函数,每次调用它都会创建一个自动增量 id,就好像它在 SQL(主键)上一样:

class Program
{
    static void Main(string[] args)
    {
        string[] dataInsert = new string[10];

        for(int i = 0; i < dataInsert.Length; i++)
        {
            dataInsert[i] = Convert.ToString(generateId());
        }

        for (int i = 0; i < dataInsert.Length; i++)
        {
            Console.WriteLine(dataInsert[i]);
        }

        Console.ReadKey();
    }
    static int generateId()
    {
        int id = 1;
        return id += 1;
    }
}

【问题讨论】:

  • 这个 id 是否意味着在程序运行期间保持不变?还是每次运行程序时只需要从 1 开始?
  • 第一次从1开始,每次调用函数递增一次
  • 我明白了,但是在您停止程序并重新启动它之后,它应该从 1 开始还是从最后一个数字开始?如果您希望它从最后一个数字开始,您需要将数字保存在某处(数据库、文件等)
  • 应该从最后一个数字开始,我把txt上的文件插入了
  • 如果程序的两个实例同时运行会发生什么?

标签: c#


【解决方案1】:

您可以创建一个 static 整数来记住先前返回的 id,然后使用 Interlocked.Increment() 根据需要递增它:

using System.Threading;


class Program
{
    static int lastId = 0;

    static int generateId()
    {
        return Interlocked.Increment(ref lastId);
    }

    // Remainder of Program unchanged
}

Interlocked.Increment 递增指定变量并将结果存储为原子操作并返回递增后的值。保证在不同线程调用generateId()时不会返回重复的ID。

请注意文档中的以下remark

此方法通过包装处理溢出条件:if location = Int32.MaxValue, location + 1 = Int32.MinValue。不抛出异常。

因此,您可能需要向generateId() 添加逻辑来检查并抛出异常。

要进一步了解静态字段以及何时使用它们,请参阅:

更新

在 cmets 中,提出了以下问题:如果我们不知道有多个线程(即假设这是一个单线程应用程序),为什么这里需要Interlocked.Increment

此时应该始终假定应用是多线程的。如果有一个简单的、线程安全的替代方案可以在没有显着额外成本(在开发成本或运行时性能方面)使用时,不应该使用线程不安全模式,就像这里的情况一样。由于OP 自称是马德拉大学的学生,他们应该开始学习线程安全模式,即使是在编写控制台应用程序时,这样他们以后就不需要忘记线程不安全技术.

【讨论】:

  • 如果我们不知道有多个线程(即假设这是一个单线程应用程序),为什么这里需要Interlocked.Increment
  • 需要额外付费。与单个增量相比,处理该互锁有很多开销。然而,我遇到了一个最近的问题,我试图用多个线程做一些工作,而我使用的库之一不是线程安全的,并且一直导致随机崩溃。那很烦人! :-) 知道如何编写线程安全代码很重要,但我不会说你总是需要这样做。尤其是当它是您完全可以控制的有趣的小应用程序时。如果它是您计划共享的库,那么当然可以。你应该。
  • 与单个增量相比,处理该联锁的开销很多有任何证据吗? this answerthis article 表示性能损失是 36-90 个周期,这对于像 ID 生成器这样的东西来说是微不足道的,只有在某些紧密循环中使用时才会变得显着。但是我对开发成本而不是性能成本更感兴趣,并且Interlocked.Increment在这里就像增量运算符一样简单。
  • Interlocked.Increment(ref id) 需要比 Id++ 更多的时间来键入。这比执行所需的 4-5 倍多得多的开发时间;-) 他们应该缩写它。 IntLk.Inc 可能吗? :)
【解决方案2】:

改变

static int generateId()
{
    int id = 1;   //This resets the value to 1 every time you enter.
    return id+= 1;
}

收件人:

private static int id = 1;
static int generateId()
{
    return id++;
}

您的 generateId 将始终返回 2,因为您传递的本地值在每次输入时都初始化为 1。在我的示例中,当应用程序运行时,Id 将设置为 1,然后递增。不过,它总是从 1 开始。

添加局部变量、字段变量和静态变量的说明。

当你像你一样定义一个变量时,一个局部变量,它只存在于方法的范围内,并且每次调用方法时都会重新初始化。

您还可以定义只要存在对象实例就存在的字段变量。例如:

public class AutoIncrment
{
    private int id = 1;
    public int GenerateId()
    {
       return id++;
    }
}

你可以这样使用它:

var idState = new AutoIncrement();

console.WriteLine(idState.GenerateId()); // Outputs 1
console.WriteLine(idState.GenerateId()); // Outputs 2 
console.WriteLine(idState.GenerateId()); // Outputs 3 
console.WriteLine(idState.GenerateId()); // Outputs 4 .. And so on

var idState2 = new AutoIncrement();  // Create a new instance and it starts over

console.WriteLine(idState2.GenerateId()); // Outputs 1
console.WriteLine(idState2.GenerateId()); // Outputs 2 .. And so on
// Go back to idState object and it will keep going from where you last left off
console.WriteLine(idState.GenerateId()); // Outputs 5 

然后有一些静态变量,就像我在顶部的答案一样。它们作为类本身的一部分存在。由于类在程序运行时始终存在,因此变量也存在于内存中。

【讨论】:

  • 不错的答案,但考虑到 OP 是个新手,我认为对 static 的一点描述会受益匪浅。
  • 我会遵守的。 :-)
【解决方案3】:

您的代码总是在 generateid() 方法中返回 2

       static int id =1;
       for(int i=0;i<dataInsert.Length;i++)
        {
            dataInsert[i] = Convert.ToString(generateId());
        }

        static int generateId()
        {

          return id+= 1;
        }

【讨论】:

    【解决方案4】:

    只需要将您的 int 设为静态即可。

    也在类空间中声明。不在函数中。

    【讨论】:

    • int 怎么可能是静态的?
    猜你喜欢
    • 2011-01-10
    • 2011-07-01
    • 1970-01-01
    • 2012-03-04
    • 1970-01-01
    • 1970-01-01
    • 2022-09-29
    • 2016-09-27
    • 2015-05-25
    相关资源
    最近更新 更多