-
-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
$"" パフォーマンス改善 #42
Comments
https://gist.github.com/ufcpp/233d33b0220215bb5bdf2a10e8a434bf#file-benchmark-cs 手元の結果:
古いの
|
// 多分リーク(ArrayPool への Return が掛からない)
var ss = $"{x} {m() ?? throw new Exception()}"; 一応、現状の ArrayPool の実装上、 Return が掛からなくても、「毎度配列が new されて Pool の意味がない」以上のペナルティはないらしい。 |
var t = Task.Delay(1).ContinueWith(_ => 1);
string s = $"{x} / {await t} / {z}"; // これは string.Format になっちゃう。 var t = await Task.Delay(1).ContinueWith(_ => 1);
DefaultInterpolatedStringHandler s = $"{x} / {t} / {z}"; // これはそもそもコンパイルエラー。 var t = await Task.Delay(1).ContinueWith(_ => 1);
string s = $"{x} / {t} / {z}"; // これは大丈夫。AppendFormatted 出てる |
// $"" はカルチャー依存
var x = 1234;
var y = 1.234;
var z = new DateOnly(2001, 2, 3);
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-fr");
// カルチャー依存を避けたければこれを使う。
var s = string.Create(
CultureInfo.InvariantCulture,
$"{x} / {y} / {z}");
Console.WriteLine(s); |
//var s = string.Create(
// CultureInfo.InvariantCulture,
// $"{x} / {y} / {z}");
//
// ↓こう展開される
DefaultInterpolatedStringHandler h = new(6, 3, CultureInfo.InvariantCulture);
h.AppendFormatted(x);
h.AppendLiteral(" / ");
h.AppendFormatted(y);
h.AppendLiteral(" / ");
h.AppendFormatted(z);
// 展開、ここまで
var s = h.ToStringAndClear(); // string.Create の中はこれ1行。
Console.WriteLine(s); |
//var s = string.Create(
// CultureInfo.InvariantCulture,
// stackalloc char[128],
// $"{x} / {y} / {z}");
//
// ↓こう展開される
DefaultInterpolatedStringHandler h = new(
6, 3,
CultureInfo.InvariantCulture,
stackalloc char[128]); |
// ref がつかない struc なら間に await があっても平気
C.M($"{1} / {await Task.Delay(1).ContinueWith(_ => 2)} / {3}");
class C
{
//public static void M(string _) => Console.WriteLine("string");
public static void M(DummyHandler _) => Console.WriteLine("DummyHandler");
}
// これが $"" を受け取れる最低ラインのパターン。
[System.Runtime.CompilerServices.InterpolatedStringHandler]
public class DummyHandler |
C.M("");
C.M($""); // string
C.M($"{""}"); // string
const string a = "aaa";
C.M($"{""} {a}"); // string
C.M($"{1}"); // DummyHandler
string b = "aaa";
C.M($"{b}"); // DummyHandler
int x = 1;
C.M($"{x}"); // DummyHandler
class C
{
public static void M(string _) => Console.WriteLine("string");
public static void M(DummyHandler _) => Console.WriteLine("DummyHandler");
} |
using System.Runtime.CompilerServices;
var a = 1;
write<int>(new[] { "X", "Y", "Z" }, $"{1}{2}{a}");
// 素直にこうしろよという説はある。
//new Dictionary<string, object>
//{
// ["X"] = 1,
//}
static void write<TValue>(
string[] keys,
[InterpolatedStringHandlerArgument("keys")]
ParamsDictionaryHandler<TValue> handler)
{
var dic = handler.Dictionary;
foreach (var (key, value) in dic)
{
Console.WriteLine($"{key}: {value}");
}
}
[InterpolatedStringHandler]
public struct ParamsDictionaryHandler<T>
{
internal readonly Dictionary<string, T> Dictionary;
private readonly string[] _keys;
private int _i = 0;
public ParamsDictionaryHandler(int _, int formattedCount, string[] keys)
{
_keys = keys;
Dictionary = new(formattedCount);
}
public void AppendFormatted(T value)
{
Dictionary[_keys[_i]] = value;
_i++;
}
} |
// M(string) をコメントアウトすると…
C.M(""); // ダメ。
// M(string) の有無で呼ばれる先が違う。
C.M($""); // OK。
C.M($"{"abc"}"); // OK。
class C
{
//public static void M(string _) => Console.WriteLine("string");
public static void M(DummyHandler _) => Console.WriteLine("DummyHandler");
} |
C.M($""); // ダメ。
C.M($"{"abc"}"); // ダメ。
// キャスト挟めばOK。
C.M((DummyHandler)$""); // OK。
C.M((DummyHandler2)$"{"abc"}"); // OK。
// as とかはダメ。
C.M($"" as DummyHandler); // ダメ。
C.M((DummyHandler)""); // ダメ。
// IFormattable も同じようなもの。
var xx1 = (IFormattable)$""; // OK
var xx2 = $"" as IFormattable; // ダメ
class C
{
// わざとオーバーロード解決できなくする。
public static void M(DummyHandler _) => Console.WriteLine("DummyHandler");
public static void M(DummyHandler2 _) => Console.WriteLine("DummyHandler2");
} |
using System.Text;
var sb = new StringBuilder();
sb.Append($"{1}"); // AppendInterpolatedStringHandler が呼ばれる。
var tw = new TextWriter(); // TextWriter には同様のオーバーロードはなさげ… |
// 完全なアロケーション0フォーマット。
Span<char> buffer = stackalloc char[128];
buffer.TryWrite($"{1}.{2}", out var charWritten); |
true invariant culture string interpolation は多少作りたい… |
Console.WriteLine(DateTime.Parse("平成35/1/1"));
Console.WriteLine(DateTime.Parse("昭和100/1/1"));
Console.WriteLine(DateTime.Parse("昭和2000/1/1"));
Console.WriteLine(DateTime.Parse("9999/1/1"));
// さすがにダメっぽい。
//Console.WriteLine(DateTime.Parse("平成元年1月1日"));
// FormatException
//Console.WriteLine(DateTime.Parse("昭和-1/1/1"));
// 以下の2つは範囲外だけど FormatException
//Console.WriteLine(DateTime.Parse("昭和9999/1/1"));
//Console.WriteLine(DateTime.Parse("10000/1/1")); |
6 tasks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
配信URL: https://youtu.be/P7-kykSvCmk
#41 残作業その1。
https://twitter.com/ufcpp/status/1425773277834711046
https://gist.github.com/ufcpp/233d33b0220215bb5bdf2a10e8a434bf
https://ufcpp.net/blog/2021/8/net6p7/#interpolated-string
https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/improved-interpolated-strings.md
たぶん、これ単品で1配信になる。
The text was updated successfully, but these errors were encountered: