尽管 JIT 有能力在编译时消除掉多余的分支(因为 T
在编译时已知),编写起来仍然非常费劲,并且无法处理没有覆盖到的情况 。
但现在我们只需要利用接口的虚静态方法,即可高效的对所有实现了 IParsable<T>
的类型实现这个 Parse
方法 。.NET 标准库中已经内置了不少相关类型,例如 System.IParsable<T>
的定义如下:
public interface IParsable<TSelf> where TSelf : IParsable<TSelf>?{abstract static TSelf Parse(string s, IFormatProvider? provider);abstract static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out TSelf result);}
那么,我们只需要编写一个:
T Parse<T>(string str) where T : IParsable<T>{return T.Parse(str, null);}
即可 。
这样,哪怕是其他地方定义的类型,只要实现了 IParsable<T>
,就能够传到这个方法中:
struct Point : IParsable<Point>{public int X, Y;public static Point Parse(string s, IFormatProvider? provider) { ... }public static bool TryParse(string? s, IFormatProvider? provider, out Point result) { ... }}
当然,既然是虚静态方法,那就意味着不仅仅可以是 abstract
,更可以是 virtual
的,如此一来我们还可以提供自己的默认实现:
interface IFoo{virtual static void Hello() => Console.WriteLine("hello");}
Dispose
和 IDisposable
我们有时需要显式地手动控制资源释放,而不是一味地交给 GC 来进行处理,那么此时我们的老朋友 Dispose
就派上用场了 。
对于 class
、struct
和 record
而言,我们需要为其实现 IDisposable
接口,而对于 ref struct
而言,我们只需要暴露一个 public void Dispose()
。这样一来,我们便可以用 using
来自动进行资源释放 。
例如:
// 在 foo 的作用域结束时自动调用 foo.Dispose()using Foo foo = new Foo();// ...// 显式指定 foo 的作用域using (Foo foo = new Foo()){// ...}struct Foo : IDisposable{private void* memory;private bool disposed;public void Dispose(){if (disposed) return;disposed = true;NativeMemory.Free(memory);}}
异常处理的编译优化异常是个好东西,但是也会对效率造成影响 。因为异常在代码中通常是不常见的,因为 JIT 在编译代码时,会将包含抛出异常的代码认定为冷块(即不会被怎么执行的代码块),这么一来会影响 inline 的决策:
void Foo(){// ...throw new Exception();}
例如上面这个 Foo
方法,就很难被 inline 掉 。
但是,我们可以将异常拿走放到单独的方法中抛出,这么一来,抛异常的行为就被我们转换成了普通的函数调用行为,于是就不会影响对 Foo
的 inline 优化,将冷块从 Foo
转移到了 Throw
中:
[DoesNotReturn] void Throw() => throw new Exception();void Foo(){// ...Throw();}
考虑到目前 .NET 还没有 bottom types 和 union types,当我们的 Foo
需要返回东西的时候,很显然上面的代码会因为不是所有路径都返回了东西而报错,此时我们只需要将 Throw
的返回值类型改成我们想返回的类型,或者干脆封装成泛型方法然后传入类型参数即可 。因为 throw
在 C# 中隐含了不会返回的含义,编译器遇到 throw
时知道这个是不会返回的,也就不会因为 Throw
没有返回东西而报错:
[DoesNotReturn] int Throw1() => throw new Exception();[DoesNotReturn] T Throw2<T>() => throw new Exception();int Foo1(){// ...return Throw1();}int Foo2(){// ...return Throw2<int>();}
经验总结扩展阅读
- 二、.Net Core搭建Ocelot
- 一千零一夜柏海的结局是什么?
- 创建.NET程序Dump的几种姿势
- 中国6大奇葩零食排行榜
- 干无花果怎么吃
- 零食可以托运吗
- C# 8.0 添加和增强的功能【基础篇】
- .NET性能系列文章二:Newtonsoft.Json vs. System.Text.Json
- 某 .NET RabbitMQ SDK 有采集行为,你怎么看?
- .net core Blazor+自定义日志提供器实现实时日志查看器