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 解析方案。
备注:内容仅供参考。
