从此

C#.NET、CSharp 语法新特性

综合/最新

C#编程

通用

锁定 .NET SDK 版本 echo '{ "sdk": { "version": "9.0.100-preview.6.24328.19" } }' > my-project/global.json
  或通过命令生成 dotnet new globaljson --sdk-version 8.0.100 --force

添加仓库源 dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org
  dotnet nuget add source https://someServer/myTeam -n myTeam -u myUsername -p myPassword

直接引用 C# 库项目 <ItemGroup><ProjectReference Include="D:\x\x.csproj" /></ItemGroup>
物理合并 C# 库项目 <Import Project="..\x\SharedProject.projitems" Label="Shared" />
发布至 NuGet 仓库 dotnet nuget push ".godot\x\x.1.0.0-alpha.$time.nupkg" --api-key [API KEY] --source "https://nuget.pkg.github.com/[USER]/index.json"

VS2026 免费社区版 - https://aka.ms/vs/stable/vs_community.exe
VS2026 Headless 命令行工具 - https://aka.ms/vs/stable/vs_buildtools.exe

变量类型默认值(用到对象时不触发构造函数):int i = default; // 即=0。
初始化:Button btn = new();
初始化器:new List{ new Player("x"), new Player("xx") }; // 比Java少写个大括号。
调父类构造函数:public class NewClass : FatherClass { public NewClass() : base() { } } // Java 则写在方法体内 super();
类型判断:typeof(IEnumerable).IsAssignableFrom(typeof(List)) // 左侧更抽象。
判null:ArgumentNullException.ThrowIfNull(obj);
重写(覆写)/隐藏:
  声明类型 obj = new 定义子类型(); // override 不关心声明类型,而 new 则会分开调用声明类型里的方法体。
  override(重写)关键词则会把基类同名方法也编译为子类方法体,但基类必须标注为abstract(无方法体)或virtual(有方法体)。
  new(隐藏)关键词用于子类方法隐藏基类同名方法,转为基类后,则调用基类的方法体。

返回多个值(ValueTuple):
  private (int, int) GetNumbers()
  {
    return (1, 2);
  }

记录定义:
  public record Range(string name, int? p = null)
  { public int min { get; init; } public int max { get; init; } public string x { get; init; } }
记录调用:new Range("x") { min = 1, max = 9 } // name字段外均可选。

析构函数:
    ~Attack() { GD.Print("GC Attack."); }

await/async多层:
  public async void layer1(){ await layer2(); }
  public async Task layer2(){ await layer3(); }

内存屏障(Memory Barrier):
  new CancellationToken(false) 相比 boolean 的 isRunning 多处理了内存屏障(Memory Barrier)。
  父级取消要联动子级,子级关闭则不影响父级。

特性:
  变相支持自定义类的返回值: [MyAttribute(nameof(MyClass.MethodName))]

C# 14 为现存类(声明在入参)扩展实例方法或属性:
  public static class CollectionExtensions
  {
    extension(ICollection collection)
    {  // 列表类会多个属性 list.IsEmptyNew()
       public bool IsEmptyNew => this.Count == 0;
    }
  }

  关键词 internal 反射:
    // 如果是外部 DLL,先用 Assembly.Load 获取程序集,再 GetType;internal static class Http3ControlStreamReader { }
    Type staticClassType = typeof(WebTransportClientTransportOptions).Assembly.GetType("MyNS.Internal.Http3ControlStreamReader");

    // 注意:寻找静态方法必须包含 BindingFlags.Static
    var staticMethod = staticClassType.GetMethod(
        "AcceptAndReadSettingsAsync",
        BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic
    );

    // 准备调用参数(假设方法需要两个参数)
    object[] parameters = new object[] { quicConnection, _logger, cancellationToken };

    // 🌟 重点:因为是静态方法,Invoke 的第一个参数固定传 null!
    dynamic result = staticMethod.Invoke(null, parameters);
    await result.ConfigureAwait(false);


  反射构造函数:
    // 1. 获取程序集(如果已经引用,可以通过其中一个公开类来获取,或者通过名字加载)
    //var assembly = Assembly.Load("YourTargetAssembly");
    var assembly = Assembly.GetAssembly(typeof(WebTransportClientTransportOptions));
    // 或者如果已知其中一个公开类型:Assembly.GetAssembly(typeof(WebTransportClientTransportOptions));
    // 2. 通过全限定名获取 internal 类
    Type pulseSessionType = assembly.GetType("MyNS.WebTransportClientPulseSession");
    if (pulseSessionType == null)
    {
        Console.WriteLine("未找到该类,请检查命名空间和程序集名称是否正确。");
        return null;
    }
    GD.Print("pulseSessionType - " + pulseSessionType);

    // 1. 获取构造函数的参数类型数组 (Type[])
    // 注意:即使最后两个参数有默认值,也必须把它们的类型写完整!
    Type[] constructorTypes = new Type[]
    {
        typeof(QuicConnection),                                 // quicConnection
        typeof(IReadOnlyDictionary),            // queryParameters (可空引用类型在反射中依然是原类型)
    };

    // 2. 查找构造函数
    ConstructorInfo ctor = pulseSessionType.GetConstructor(
        BindingFlags.Instance | BindingFlags.Public,
        null,
        constructorTypes,
        null
    );

    if (ctor == null)
    {
        Console.WriteLine("未能匹配到对应的构造函数,请检查参数类型是否完全一致。");
    }
    GD.Print("ctor - " + ctor);
    object[] parameters = new object[] { (QuicConnection)null, null };
    object pulseSessionInstance = ctor.Invoke(parameters);


软件时效:
  var today = DateOnly.FromDateTime(DateTime.UtcNow);
  if (today > new DateOnly(2026, 2, 1))
  {
	var msg = "程序已过期,将于10秒后退出!";
	Task.Delay(10_000).ContinueWith(_ => { System.Environment.Exit(0); });
	MessageBox.Show(msg); // or OS.Alert(msg);
  }

MSBUILD 输出变量:
  <Target Name="x" BeforeTargets="PrepareForBuild">
    <Message Text="Output: $(WinInstallType)" Importance="high" />
  </Target>

判断Windows Server还是Windows 桌面版(Client):
  <!-- Output:Server、Client -->
  <WinInstallType>$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion@InstallationType)</WinInstallType>
  <PublishAot Condition="$(WinInstallType.Contains('Client'))">false</PublishAot>

使调库者能访问 protected internal readonly Node Wrapped;
  <ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
      <_Parameter1>arpg-statecharts</_Parameter1>
    </AssemblyAttribute>

    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
      <_Parameter1>Chinatown Ranger</_Parameter1>
    </AssemblyAttribute>
  </ItemGroup>

隐藏调库者同名类:
  <ItemGroup>
    <Compile Remove="addons\godot_state_charts\csharp\**" />
  </ItemGroup>

其他

AOT交叉编译 - https://learn.microsoft.com/zh-cn/dotnet/core/deploying/native-aot/cross-compile
获取 PE 头时间戳 - https://verrickt.github.io/2018/10/22/get-link-time-from-csharp/