标签 C# 下的文章

场景:
在一个工厂ERP管理系统中,有部分实体的界面需要显示相关联的其它信息,而这部分信息是弱连接的,需要调用WebAPI取回,传统的方式是一一取回,结果是用户感知的速度达不到要求。
使用BackgroundWorker,在后台取资料,取完资料后再显示,如果取资料的过程中,主实体已经变更了,或者已多次变更了,则等上次任务完成后,直接再取最后一次变更的资料,中间的直接丢弃,既加快了速度,也节省了资源。
实现思路:

先加入BackgroundWorker,(命名如:BackgroundWorker_ShowItem)。

再定义两个变量,用于保存要显示的主实体(或其关联键)

private T Item = null;
private T NextItem = null;

当需要显示一个主体的内容时,不直接显示,而是呼叫BackgroundWorker来处理

public void ShowItem(T item)
{
    if (BackgroundWorker_ShowItem.IsBusy)
    {
    this.NextItem = item;
    }
    else
    {
    this.Item = item;
    this.BackgroundWorker_ShowItem.RunWorkerAsync();
    }
}

private void BackgroundWorker_ShowItem_DoWork(object sender, DoWorkEventArgs e)
{
    this.ShowItem();
}

private void BackgroundWorker_ShowItem_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (this.NextItem != null)
    {
    var nextItem = this.NextItem;
    this.NextItem = null;
    this.ShowItem(nextItem);
    }
}

注意,当ShowItem()中有访问前端时,会报“线程间操作无效”的例外,需要使用Invoke,但不要在DoWork中将ShowItem()全部包含,而应该在ShowItem()中单独处理。否则达不到性能优化的效果。

在C#中,implicit operatorexplicit operator 都用于用户定义的类型转换,但它们在转换方式和安全性上有重要区别。

1. implicit operator(隐式转换)

特点:

  • 自动进行,不需要显式类型转换
  • 转换是安全的,不会丢失数据或引发异常
  • 编译器自动识别并执行转换

示例代码:

public class Celsius
{
    public double Temperature { get; set; }
    
    public Celsius(double temp)
    {
        Temperature = temp;
    }
    
    // 隐式转换:double → Celsius
    public static implicit operator Celsius(double d)
    {
        return new Celsius(d);
    }
    
    // 隐式转换:Celsius → double
    public static implicit operator double(Celsius c)
    {
        return c.Temperature;
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        // 隐式转换 - 自动进行
        Celsius c = 25.5;           // double 自动转为 Celsius
        double temp = c;            // Celsius 自动转为 double
        
        Console.WriteLine($"温度: {temp}°C"); // 输出: 温度: 25.5°C
        
        // 在方法调用中也自动转换
        DisplayTemperature(30.0);   // double 自动转为 Celsius
    }
    
    static void DisplayTemperature(Celsius celsius)
    {
        Console.WriteLine($"显示温度: {celsius.Temperature}°C");
    }
}

2. explicit operator(显式转换)

特点:

  • 必须显式指定类型转换
  • 可能丢失数据或引发异常
  • 需要程序员明确意图

示例代码:

public class Money
{
    public decimal Amount { get; set; }
    public string Currency { get; set; }
    
    public Money(decimal amount, string currency)
    {
        Amount = amount;
        Currency = currency;
    }
    
    // 显式转换:Money → decimal(可能丢失货币信息)
    public static explicit operator decimal(Money money)
    {
        return money.Amount;
    }
    
    // 显式转换:decimal → Money(需要指定默认货币)
    public static explicit operator Money(decimal amount)
    {
        return new Money(amount, "USD");
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        Money salary = new Money(5000.00m, "USD");
        
        // 显式转换 - 必须明确指定
        decimal amount = (decimal)salary;        // Money → decimal
        Money money = (Money)2500.00m;           // decimal → Money
        
        Console.WriteLine($"金额: {amount}");    // 输出: 金额: 5000.00
        Console.WriteLine($"货币: {money.Currency}, 金额: {money.Amount}");
        
        // 如果不使用显式转换,编译器会报错
        // decimal wrong = salary; // 错误: 无法隐式转换
    }
}

3. 综合对比示例

public class Distance
{
    public double Meters { get; set; }
    
    public Distance(double meters)
    {
        Meters = meters;
    }
    
    // 隐式转换:int → Distance(总是安全的)
    public static implicit operator Distance(int meters)
    {
        return new Distance(meters);
    }
    
    // 显式转换:Distance → int(可能丢失精度)
    public static explicit operator int(Distance d)
    {
        return (int)d.Meters;
    }
    
    // 隐式转换:double → Distance(总是安全的)
    public static implicit operator Distance(double meters)
    {
        return new Distance(meters);
    }
    
    // 显式转换:Distance → double(安全,但为了对称性使用显式)
    public static explicit operator double(Distance d)
    {
        return d.Meters;
    }
    
    public override string ToString()
    {
        return $"{Meters}米";
    }
}

class Program
{
    static void Main()
    {
        // 隐式转换示例
        Distance d1 = 100;          // int → Distance (隐式)
        Distance d2 = 123.45;       // double → Distance (隐式)
        
        Console.WriteLine($"d1: {d1}"); // 输出: d1: 100米
        Console.WriteLine($"d2: {d2}"); // 输出: d2: 123.45米
        
        // 显式转换示例
        int metersInt = (int)d2;    // Distance → int (显式,丢失精度)
        double metersDouble = (double)d2; // Distance → double (显式)
        
        Console.WriteLine($"整数米数: {metersInt}");   // 输出: 整数米数: 123
        Console.WriteLine($"精确米数: {metersDouble}"); // 输出: 精确米数: 123.45
        
        // 在运算中的使用
        Distance total = d1 + 50;   // 隐式转换 50 → Distance
        Console.WriteLine($"总距离: {total}"); // 输出: 总距离: 150米
    }
}

4. 关键区别总结

特性implicit operatorexplicit operator
转换方式自动必须显式指定
安全性安全,不会丢失数据可能不安全,可能丢失数据
使用场景无损转换、小范围到大范围有损转换、大范围到小范围
编译器行为自动识别转换需要强制类型转换语法
代码可读性更简洁更明确意图

5. 最佳实践建议

  1. 使用 implicit operator 当:

    • 转换100%安全
    • 不会丢失信息
    • 转换是直观的
  2. 使用 explicit operator 当:

    • 可能丢失数据或精度
    • 转换可能失败
    • 需要用户明确转换意图
  3. 避免过度使用隐式转换,以免降低代码可读性。

这种机制让C#能够提供灵活的类型转换,同时保持类型安全性和代码清晰度。