July 1, 2023
By: Kevin

C#中的一些小技巧

  1. 字符串和二进制写入文件
  2. 反编译dll的工具, 用来查看dll中的信息,包括namespace, class, functions.
  3. 动态载入dll的类
  4. 获取UniqID
  5. 获取环境信息
  6. Task的异常处理
    1. is 表达式
  7. 模式匹配
    1. NULL检查
    2. NOT 表达式
    3. 针对枚举类型
    4. 针对字符串类型
    5. 关系模型
    6. 多个输入
    7. 列表模式 (c# 11才支持)
    8. TODO 模式匹配中的运算符 [模式匹配中的运算符]
  8. 退出应用程序
  9. 获取当前目录
  10. 获取临时文件&目录
  11. 字符串或者字符串数组写入文件
  12. 获取类型名称
  13. Dictionary

字符串和二进制写入文件

System.IO.File.WriteAllBytes(@"object.bin", bs);
System.IO.File.WriteAllText(@"s0file.txt", s0);

反编译dll的工具, 用来查看dll中的信息,包括namespace, class, functions.

  • ilspy, macos/windows都可以用, mac下安装

brew install --cask ilspy

动态载入dll的类

如果是程序已经载入的dll, 可以用Type taskType = Type.GetType($"MyClass"); 来载入其中的类 对于需要动态载入的, 需要:

string relativePath = "./ExampleSubTasks.dll";
string absolutePath = Path.GetFullPath(relativePath);
Assembly assembly = Assembly.LoadFile(absolutePath);
Type taskType = assembly.GetType(typeName);

获取UniqID

Console.WriteLine(Guid.NewGuid().ToString().Replace("-", ""));

获取环境信息

using System.Runtime.InteropServices;
// 获取当前操作系统的版本信息
OperatingSystem os = Environment.OSVersion;
Version version = os.Version;

// 使用 RuntimeInformation 获取操作系统信息
string osDescription = RuntimeInformation.OSDescription;
Architecture osArch = RuntimeInformation.OSArchitecture;

Console.WriteLine("操作系统版本: " + version);
Console.WriteLine("操作系统描述: " + osDescription);
Console.WriteLine("操作系统架构: " + osArch);

Task的异常处理

Task中异步执行的异常悄无声息

 AppDomain.CurrentDomain.UnhandledException += (o, e ) =>
     Console.WriteLine($"Unhandled exception occurs {e.ExceptionObject}.");
_ =  Task.Run(() => throw new Exception("DoWork failed."));
await Task.Delay(100);
Console.WriteLine("没有错误");

只有阻塞式的才会有异常抛出.

 AppDomain.CurrentDomain.UnhandledException += (o, e ) =>
     Console.WriteLine($"Unhandled exception occurs {e.ExceptionObject}.");
await  Task.Run(() => throw new Exception("DoWork failed."));
await Task.Delay(100);

但是, 很多时候我们就是不想阻塞呀…可以每次都try, catch, 可以解决问题, 就是有点麻烦

try {
    await Task.Run(() => {

        throw new Exception("DoWork failed.");
    });
}
catch (Exception e) {Console.WriteLine(e.StackTrace);}

await Task.Delay(100);

我们有个更好的方式

public static class TaskExtensions
{
    public static Task FailFastOnException(this Task task)
    {
        task.ContinueWith(c => Environment.FailFast("Task faulted", c.Exception),
                          TaskContinuationOptions.OnlyOnFaulted); // 例外發生時才執行。
        return task;
    }

    public static Task IgnoreExceptions(this Task task)
    {
        task.ContinueWith(c => Console.WriteLine(c.Exception),
                          TaskContinuationOptions.OnlyOnFaulted); // 例外發生時才執行。
        return task;
    }
}
Task.Run(() => throw new Exception("DoWork failed.")).FailFastOnException();

is 表达式

  1. 检查表达式的类型

    int i = 34;
    object iBoxed = i;
    int? jNullable = 42;
    if (iBoxed is int a && jNullable is int b)
    {
        Console.WriteLine(a + b);  // output 76
    }
    
  2. 检查是否为null

    string input = null;
    if (input is null)
    {
        Console.WriteLine("null");
    }
    
  3. 使用 否定模式 检查null

    string result = "a";
    if (result is not null)
    {
        Console.WriteLine(result.ToString());
    }
    

模式匹配

NULL检查

int? maybe = 12;

if (maybe is int number)
{
    Console.WriteLine($"The nullable int 'maybe' has the value {number}");
}
else
{
    Console.WriteLine("The nullable int 'maybe' doesn't hold a value");
}

NOT 表达式

#nullable enable
string? message = "This is not the null string";

if (message is not null)
{
    Console.WriteLine(message);
}

针对枚举类型

public enum Operation
{SystemTest, Start, Stop, Reset };

public string PerformOperation(Operation command) =>
    command switch
{
    Operation.SystemTest => "",
    Operation.Start => "",
    Operation.Stop => "",
    Operation.Reset => "",
    _ => throw new ArgumentException("Invalid enum value for command", nameof(command)),
};
#+results: 

针对字符串类型

public int PerformOperation(string command) =>
   command switch
   {
       "SystemTest" => 1,
       "Start" => 2,
       "Stop" => 3,
       "Reset" => 4,
       _ => throw new ArgumentException("Invalid string value for command", nameof(command)),
   };
#+results: 

关系模型

string WaterState(int tempInFahrenheit) =>
    tempInFahrenheit switch
    {
        (> 32) and (< 212) => "liquid",
        < 32 => "solid",
        > 212 => "gas",
        32 => "solid/liquid transition",
        212 => "liquid / gas transition",
    };
#+results: 

多个输入

public record Order(int Items, decimal Cost);

public decimal CalculateDiscount(Order order) =>
    order switch
    {
        { Items: > 10, Cost: > 1000.00m } => 0.10m,
        { Items: > 5, Cost: > 500.00m } => 0.05m,
        { Cost: > 250.00m } => 0.02m,
        null => throw new ArgumentNullException(nameof(order), "Can't calculate discount on null order"),
        var someObject => 0m,
    };
public decimal CalculateDiscount(Order order) =>
    order switch
    {
        ( > 10,  > 1000.00m) => 0.10m,
        ( > 5, > 50.00m) => 0.05m,
        { Cost: > 250.00m } => 0.02m,
        null => throw new ArgumentNullException(nameof(order), "Can't calculate discount on null order"),
        var someObject => 0m,
    };

列表模式 (c# 11才支持)

decimal balance = 0m;
foreach (string[] transaction in ReadRecords())
{
    balance += transaction switch
    {
        [_, "DEPOSIT", _, var amount]     => decimal.Parse(amount),
        [_, "WITHDRAWAL", .., var amount] => -decimal.Parse(amount),
        [_, "INTEREST", var amount]       => decimal.Parse(amount),
        [_, "FEE", var fee]               => -decimal.Parse(fee),
        _                                 => throw new InvalidOperationException($"Record {string.Join(", ", transaction)} is not in the expected format!"),
    };
    Console.WriteLine($"Record: {string.Join(", ", transaction)}, New balance: {balance:C}");
}
#+results: 

TODO 模式匹配中的运算符 [模式匹配中的运算符]

退出应用程序

System.Envrionment.Exit(0);

获取当前目录

对于脚本执行, 就是当前脚本所在目录

对于编译执行的目录, 一般是bin的debug目录 bin\Debug\net6.0\

获取临时文件&目录

using System.IO;
Console.WriteLine(Path.GetTempFileName());
Console.WriteLine(Path.GetTempPath());

字符串或者字符串数组写入文件

string text =
    "A class is the most powerful data type in C#. Like a structure, " +
    "a class defines the data and behavior of the data type. ";

await File.WriteAllTextAsync("WriteText.txt", text);
string[] lines = { "First line", "Second line", "Third line" };
using StreamWriter file = new("WriteLines2.txt");

foreach (string line in lines)
{
    if (!line.Contains("Second"))
    {
        await file.WriteLineAsync(line);
    }
}
#+results: 

获取类型名称

public static string CSharpName(this Type type)
{
    var sb = new StringBuilder();
    var name = type.Name;
    if (!type.IsGenericType) return name;
    sb.Append(name.Substring(0, name.IndexOf('`')));
    sb.Append("<");
    sb.Append(string.Join(", ", type.GetGenericArguments()
                                    .Select(t => t.CSharpName())));
    sb.Append(">");
    return sb.ToString();
}

Console.WriteLine(CSharpName(typeof(class("s")));

Dictionary

using System;
using System.Linq;

using System.Collections.Generic;


var cities = new Dictionary<string, string>(){
    {"UK", "London, Manchester, Birmingham"},
    {"USA", "Chicago, New York, Washington"},
    {"India", "Mumbai, New Delhi, Pune"}
};

Console.WriteLine(cities["UK"]); //prints value of UK key
Console.WriteLine(cities["USA"]);//prints value of USA key
//Console.WriteLine(cities["France"]); // run-time exception: Key does not exist

//use ContainsKey() to check for an unknown key
if(cities.ContainsKey("France")){
    Console.WriteLine(cities["France"]);
}

//use TryGetValue() to get a value of unknown key
string result;

if(cities.TryGetValue("France", out result))
{
    Console.WriteLine(result);
}

Console.WriteLine("---access elements using for loop---");
//use ElementAt() to retrieve key-value pair using index
for (int i = 0; i < cities.Count; i++)
{
    Console.WriteLine("Key: {0}, Value: {1}",
                      cities.ElementAt(i).Key,
                      cities.ElementAt(i).Value);
}
Tags: c# .NET