PAYATHON 2026

C# Billing simulation:使用数组计算账单并导出 `.txt`

支付阿杰

结论

不能用 int[,] 保存商品数据。商品名称是 string,数量是 int,价格适合用 decimal,而 C# 数组只能存放同一种类型的元素。

可以先定义一个 Product 类,再创建 Product[] 数组,让每个元素保存一件商品的数据。随后遍历数组计算金额,并通过 File.WriteAllText 导出账单。

完整示例

程序要求用户按照 商品名称,数量,单价 的格式输入,例如:

Keyboard,2,199.90

完整代码如下:

using System;
using System.Globalization;
using System.IO;
using System.Text;

namespace Final_lab
{
    class Product
    {
        public string Name { get; set; }
        public int Quantity { get; set; }
        public decimal Price { get; set; }

        public decimal Total
        {
            get { return Quantity * Price; }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Factura();
        }

        static void Factura()
        {
            int productCount = ReadPositiveInt(
                "Por favor indique la cantidad de registros a ingresar...");

            Product[] products = new Product[productCount];

            for (int i = 0; i < products.Length; i++)
            {
                products[i] = ReadProduct(i + 1);
            }

            decimal grandTotal = 0m;
            StringBuilder invoice = new StringBuilder();

            invoice.AppendLine("FACTURA");
            invoice.AppendLine(new string('-', 70));
            invoice.AppendLine(
                string.Format(
                    "{0,-25} {1,10} {2,15} {3,15}",
                    "Producto",
                    "Cantidad",
                    "Precio",
                    "Total"));

            invoice.AppendLine(new string('-', 70));

            foreach (Product product in products)
            {
                grandTotal += product.Total;

                invoice.AppendLine(
                    string.Format(
                        "{0,-25} {1,10} {2,15:F2} {3,15:F2}",
                        product.Name,
                        product.Quantity,
                        product.Price,
                        product.Total));
            }

            invoice.AppendLine(new string('-', 70));
            invoice.AppendLine(
                string.Format("{0,52} {1,15:F2}", "TOTAL:", grandTotal));

            string invoiceText = invoice.ToString();

            Console.WriteLine();
            Console.WriteLine(invoiceText);

            string filePath = Path.Combine(
                Environment.CurrentDirectory,
                "factura.txt");

            File.WriteAllText(filePath, invoiceText, Encoding.UTF8);

            Console.WriteLine("La factura fue guardada en:");
            Console.WriteLine(filePath);
            Console.WriteLine("Presione una tecla para salir...");
            Console.ReadKey();
        }

        static Product ReadProduct(int productNumber)
        {
            while (true)
            {
                Console.WriteLine();
                Console.WriteLine(
                    "Producto {0}: indique nombre, cantidad y precio entre comas.",
                    productNumber);
                Console.WriteLine("Ejemplo: Keyboard,2,199.90");

                string input = Console.ReadLine();

                if (string.IsNullOrWhiteSpace(input))
                {
                    Console.WriteLine("La entrada no puede estar vacía.");
                    continue;
                }

                string[] fields = input.Split(',');

                if (fields.Length != 3)
                {
                    Console.WriteLine(
                        "Debe ingresar exactamente tres valores separados por comas.");
                    continue;
                }

                string name = fields[0].Trim();

                int quantity;
                decimal price;

                bool validQuantity = int.TryParse(
                    fields[1].Trim(),
                    out quantity);

                bool validPrice = decimal.TryParse(
                    fields[2].Trim(),
                    NumberStyles.Number,
                    CultureInfo.InvariantCulture,
                    out price);

                if (name.Length == 0)
                {
                    Console.WriteLine("El nombre del producto no puede estar vacío.");
                    continue;
                }

                if (!validQuantity || quantity <= 0)
                {
                    Console.WriteLine(
                        "La cantidad debe ser un número entero mayor que cero.");
                    continue;
                }

                if (!validPrice || price < 0)
                {
                    Console.WriteLine(
                        "El precio debe ser un número válido mayor o igual que cero.");
                    continue;
                }

                return new Product
                {
                    Name = name,
                    Quantity = quantity,
                    Price = price
                };
            }
        }

        static int ReadPositiveInt(string message)
        {
            while (true)
            {
                Console.WriteLine(message);

                int value;

                if (int.TryParse(Console.ReadLine(), out value) && value > 0)
                {
                    return value;
                }

                Console.WriteLine(
                    "Ingrese un número entero mayor que cero.");
            }
        }
    }
}

为什么原来的数组不可行

原代码声明了:

int[,] productos;

这表示一个只能存放 int 的二维数组。它无法保存商品名称,也不适合准确保存带小数的价格。

原代码还有循环变量被覆盖的问题:

for (x = 0; x < cantidad; x++)
{
    x = recibir();
}

x 本来是循环计数器,却被用户输入覆盖,可能造成元素被跳过、重复处理,甚至让循环无法正常结束。循环变量应该只表示当前的数组下标:

for (int i = 0; i < products.Length; i++)
{
    // 使用 products[i] 保存第 i 件商品
}

数组初始化的语法也不完整:

productos = new int[,];

创建数组时需要指定长度,例如:

int[,] products = new int[productCount, 2];

不过,即使补全语法,int[,] 仍然无法保存商品名称,因此不适合这里的数据结构。

金额计算方式

每件商品的小计是:

商品小计 = 数量 × 单价

代码中的写法为:

public decimal Total
{
    get { return Quantity * Price; }
}

遍历数组时,将每件商品的小计累加起来,就能得到总金额:

decimal grandTotal = 0m;

foreach (Product product in products)
{
    grandTotal += product.Total;
}

价格使用 decimal,更适合账单和货币等十进制金额计算。

导出 .txt 文件

程序先用 StringBuilder 拼接账单内容,再将结果写入文件:

string filePath = Path.Combine(
    Environment.CurrentDirectory,
    "factura.txt");

File.WriteAllText(filePath, invoiceText, Encoding.UTF8);

factura.txt 默认保存在程序的当前工作目录中。程序也会在控制台输出完整路径,方便查找文件。

输入格式注意事项

示例通过 CultureInfo.InvariantCulture 解析价格,因此小数部分需要使用 .:

Monitor,2,1250.50

不要写成:

Monitor,2,1250,50

逗号已经用作字段分隔符,这种输入会被拆成四个值。

这种简单格式也无法处理名称中含有逗号的商品。如果商品名称可能包含逗号,可以分别询问名称、数量和价格,或者使用支持引号及转义规则的标准 CSV 解析方案。

备注:内容仅供参考。