Skip to content

Instantly share code, notes, and snippets.

@B1Z0N
Last active August 23, 2022 12:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save B1Z0N/19b9dfe973b3ec2535f8e5098a96f77e to your computer and use it in GitHub Desktop.
Save B1Z0N/19b9dfe973b3ec2535f8e5098a96f77e to your computer and use it in GitHub Desktop.
using System.Runtime.CompilerServices;
using System;
public static class Program
{
public static Logger logger = new Logger { EnabledLevel = LogLevel.Error };
public static void Main()
{
// Overview
TestOrdinary();
TestBothStringAndHandlerMethods();
TestConstructor();
TestMultiple();
TestNoArgs();
TestConstString();
TestRefParam();
TestStructConstructorParam();
TestSubstitutedGeneric();
TestDependent();
}
public enum LogLevel
{
Debug = 0,
Info,
Warning,
Error,
Fatal
}
public partial class Logger
{
public LogLevel EnabledLevel;
}
[InterpolatedStringHandler]
public ref partial struct LoggerInterpolatedStringHandler
{
private DefaultInterpolatedStringHandler handler;
public LoggerInterpolatedStringHandler(int literalLength, int formattedCount, Logger logger, LogLevel level, out bool handlerIsValid)
{
handler = default;
if (logger.EnabledLevel > level)
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s) => handler.AppendLiteral(s);
public void AppendFormatted<T>(T t) => handler.AppendFormatted(t);
public string ToStringAndClear() => handler.ToStringAndClear();
public override string ToString() => handler.ToStringAndClear();
}
//////////////////////////////////////////////////////////////////////
// Ordinary custom interpolated string handler
//////////////////////////////////////////////////////////////////////
public static void TestOrdinary()
{
var name = "Fred Silberberg";
logger.Log(LogLevel.Info, $"{name} will never be printed because info is < error!");
}
public partial class Logger
{
public void Log(LogLevel level, [InterpolatedStringHandlerArgument("", "level")]LoggerInterpolatedStringHandler handler)
{
if (EnabledLevel <= level) Console.WriteLine(handler.ToString());
}
}
//////////////////////////////////////////////////////////////////////
// Both string and interpolated string handler methods overloads
//////////////////////////////////////////////////////////////////////
public static void TestBothStringAndHandlerMethods()
{
const string i = "1";
logger.LogBothStringAndHandler(LogLevel.Fatal, $"{i + "1" + $"{i + "1" + $"{i}"}"}" + $"2"); // 111112
logger.LogBothStringAndHandler(LogLevel.Fatal, $"{@"5"}jkl{(i + "2")}1{i + "9"}"); // 5jkl12119
logger.LogBothStringAndHandler(LogLevel.Fatal, $"{"1"}"); // 1
logger.LogBothStringAndHandler(LogLevel.Fatal, $"{1}"); // $"{1}" (non-const since it's int)
}
public partial class Logger
{
public void LogBothStringAndHandler(LogLevel level, [InterpolatedStringHandlerArgument("", "level")]LoggerInterpolatedStringHandler handler)
{
if (EnabledLevel <= level) Console.WriteLine(handler.ToString());
}
public void LogBothStringAndHandler(LogLevel level, string s)
{
if (EnabledLevel <= level) Console.WriteLine(s);
}
}
//////////////////////////////////////////////////////////////////////
// Interpolated string handler in constructor
//////////////////////////////////////////////////////////////////////
public static void TestConstructor()
{
var name = "jslkfjdl";
new HandlerTestStruct(logger, LogLevel.Info, $"lo{name}" + $"2");
}
public ref struct HandlerTestStruct
{
public LoggerInterpolatedStringHandler handler;
public HandlerTestStruct(Logger logger, LogLevel level, [InterpolatedStringHandlerArgument("logger", "level")]LoggerInterpolatedStringHandler handler)
{
this.handler = handler;
}
public void Print()
{
Console.WriteLine(handler.ToStringAndClear());
}
}
//////////////////////////////////////////////////////////////////////
// Multiple handlers
//////////////////////////////////////////////////////////////////////
public static void TestMultiple()
{
var name = "jslkfjdl";
MultiHandlersTest.Print($"lo{name}" + $"2", $"{name}");
}
public ref partial struct LoggerInterpolatedStringHandler
{
public LoggerInterpolatedStringHandler(int literalLength, int formattedCount, out bool handlerIsValid)
{
handler = new(literalLength, formattedCount);
handlerIsValid = true;
}
}
public static class MultiHandlersTest
{
public static void Print(
[InterpolatedStringHandlerArgument()] LoggerInterpolatedStringHandler handler1,
[InterpolatedStringHandlerArgument()] LoggerInterpolatedStringHandler handler2)
{
Console.WriteLine(handler1.ToStringAndClear());
Console.WriteLine(handler2.ToStringAndClear());
}
}
//////////////////////////////////////////////////////////////////////
// No args
//////////////////////////////////////////////////////////////////////
public static void TestNoArgs()
{
var time = DateTime.Now;
logger.LogNoArgs(LogLevel.Error, $"Error Level. CurrentTime: {time}. This is an error. It will be printed." + $"1");
}
public partial class Logger
{
public void LogNoArgs(LogLevel level, string msg)
{
if (EnabledLevel < level) return;
Console.WriteLine(msg);
}
public void LogNoArgs(LogLevel level, LoggerInterpolatedStringHandler builder)
{
if (EnabledLevel < level) return;
Console.WriteLine(builder.ToStringAndClear());
}
}
//////////////////////////////////////////////////////////////////////
// Only handler method for const interpolated string
//////////////////////////////////////////////////////////////////////
public static void TestConstString()
{
const string i = "1";
logger.Log(LogLevel.Error, $"{i + "1" + $"{i + "1" + $"{i}"}"}" + $"2"); // 111112
logger.Log(LogLevel.Error, $"{@"5"}jkl{(i + "2")}1{i + "9"}"); // 5jkl12119
logger.Log(LogLevel.Error, $"{"1"}"); // 1
logger.Log(LogLevel.Error, $"{1}"); // $"{1}" (non-const since it's int)
}
//////////////////////////////////////////////////////////////////////
// Ref param interpolated string handler
//////////////////////////////////////////////////////////////////////
public static void TestRefParam()
{
var time = DateTime.Now;
logger.LogRefParam(LogLevel.Error, $"Error Level. CurrentTime: {time}. This is an error. It will be printed." + $"1");
}
public partial class Logger
{
public void LogRefParam(LogLevel level, string msg)
{
if (EnabledLevel < level) return;
Console.WriteLine(msg);
}
public void LogRefParam(LogLevel level, ref LoggerInterpolatedStringHandler builder)
{
if (EnabledLevel < level) return;
Console.WriteLine(builder.ToStringAndClear());
}
}
//////////////////////////////////////////////////////////////////////
// Struct constructor param interpolated string handler
//////////////////////////////////////////////////////////////////////
public static void TestStructConstructorParam()
{
var s = new Struct();
s.Print($"Struct handler {"text"}");
}
public struct Struct
{
public string Name = "Mykyta";
public Struct() {}
public void Print([InterpolatedStringHandlerArgument("")] LoggerInterpolatedStringHandler handler)
{
Console.WriteLine(handler.ToStringAndClear());
}
}
public ref partial struct LoggerInterpolatedStringHandler
{
public LoggerInterpolatedStringHandler(int literalLength, int formattedCount, Struct s, out bool handlerIsValid)
{
handler = default;
if (s.Name != "Mykyta")
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
}
//////////////////////////////////////////////////////////////////////
// Substituted generic interpolated string handler
//////////////////////////////////////////////////////////////////////
public static void TestSubstitutedGeneric()
{
var name = "jslkfjdl";
var gen = new Generic<int>() { field = 5 };
gen.Print($"lo{name}" + $"2");
}
public class Generic<T>
{
public T field;
public void Print(
[InterpolatedStringHandlerArgument("")] SubstitutedGenericInterpolatedStringHandler<T> handler)
{
Console.WriteLine(handler.ToStringAndClear());
}
}
[InterpolatedStringHandler]
public ref struct SubstitutedGenericInterpolatedStringHandler<T>
{
private DefaultInterpolatedStringHandler handler;
public SubstitutedGenericInterpolatedStringHandler(int literalLength, int formattedCount, Generic<T> gen, out bool handlerIsValid)
{
handler = default;
if (gen.field.Equals(default(T)))
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s) => handler.AppendLiteral(s);
public void AppendFormatted<T>(T t) => handler.AppendFormatted(t);
public string ToStringAndClear() => handler.ToStringAndClear();
public override string ToString() => handler.ToStringAndClear();
}
//////////////////////////////////////////////////////////////////////
// Test dependent interpolated string handlers
//////////////////////////////////////////////////////////////////////
public static void TestDependent()
{
var dh = new DependentHandlers();
dh.Print($"firstHandlerText", $"secondHandlerText");
}
public class DependentHandlers
{
public string Name = "Mykyta";
public void Print(
[InterpolatedStringHandlerArgument("")] DependableInterpolatedStringHandler handler,
[InterpolatedStringHandlerArgument("", "handler")] DependentInterpolatedStringHandler dependentHandler)
{
Console.WriteLine(dependentHandler.ToStringAndClear());
}
}
// The handler that will actually "build" the interpolated string"
[InterpolatedStringHandler]
public ref struct DependentInterpolatedStringHandler
{
private DependableInterpolatedStringHandler handler;
public DependentInterpolatedStringHandler(int literalLength, int formattedCount, DependentHandlers dh, DependableInterpolatedStringHandler handler, out bool handlerIsValid)
{
this.handler = handler;
if (dh.Name != "Mykyta")
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
}
public void AppendLiteral(string s) => handler.AppendLiteral(s);
public void AppendFormatted<T>(T t) => handler.AppendFormatted(t);
public string ToStringAndClear() => handler.ToStringAndClear();
public override string ToString() => handler.ToStringAndClear();
}
[InterpolatedStringHandler]
public ref struct DependableInterpolatedStringHandler
{
private DefaultInterpolatedStringHandler handler;
public DependableInterpolatedStringHandler(int literalLength, int formattedCount, DependentHandlers dh, out bool handlerIsValid)
{
handler = default;
if (dh.Name != "Mykyta")
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s) => handler.AppendLiteral(s);
public void AppendFormatted<T>(T t) => handler.AppendFormatted(t);
public string ToStringAndClear() => handler.ToStringAndClear();
public override string ToString() => handler.ToStringAndClear();
}
}
using System.Runtime.CompilerServices;
using System;
public static class Program
{
public static void Main()
{
const string i = "1";
var logger = new Logger() { EnabledLevel = LogLevel.Warning };
logger.Log(LogLevel.Error, $"{i + "1" + $"{i + "1" + $"{i}"}"}" + $"2"); // 111112
logger.Log(LogLevel.Error, $"{@"5"}jkl{(i + "2")}1{i + "9"}"); // 5jkl12119
logger.Log(LogLevel.Error, $"{"1"}"); // 1
logger.Log(LogLevel.Error, $"{1}"); // $"{1}" (non-const since it's int)
}
static Logger GetLogger(LogLevel level)
{
return new Logger { EnabledLevel = level };
}
public enum LogLevel
{
Debug = 0,
Info,
Warning,
Error,
Fatal
}
public class Logger
{
// Initialization code omitted
public LogLevel EnabledLevel;
public void Log(LogLevel level, [InterpolatedStringHandlerArgument("", "level")]LoggerInterpolatedStringHandler handler)
{
if (EnabledLevel <= level) Console.WriteLine(handler.ToString());
}
public void Log(LogLevel level, string s)
{
if (EnabledLevel <= level) Console.WriteLine(s);
}
}
// The handler that will actually "build" the interpolated string"
[InterpolatedStringHandler]
public ref struct LoggerInterpolatedStringHandler
{
private DefaultInterpolatedStringHandler handler;
public LoggerInterpolatedStringHandler(int literalLength, int formattedCount, Logger logger, LogLevel level, out bool handlerIsValid)
{
handler = default;
if (logger.EnabledLevel > level)
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s)
{
handler.AppendLiteral(s);
}
public void AppendFormatted<T>(T t)
{
handler.AppendFormatted(t);
}
public string ToStringAndClear()
{
return handler.ToStringAndClear();
}
public override string ToString()
{
return handler.ToStringAndClear();
}
}
// see more here: https://sergeyteplyakov.github.io/Blog/c%2310/2021/11/08/Dissecing-Interpolated-Strings-Improvements-In-CSharp-10.html
}
using System.Runtime.CompilerServices;
using System;
public static class Program
{
public static void Main()
{
var name = "jslkfjdl";
var a = new A($"lo{name}" + $"2");
}
public ref struct A
{
public string Name = "Mykyta";
public ConstructorInterpolatedStringHandler handler;
public A([InterpolatedStringHandlerArgument("")] ConstructorInterpolatedStringHandler handler)
{
this.handler = handler;
}
public void Print()
{
Console.WriteLine(handler.ToStringAndClear());
}
}
// The handler that will actually "build" the interpolated string"
[InterpolatedStringHandler]
public ref struct ConstructorInterpolatedStringHandler
{
private DefaultInterpolatedStringHandler handler;
public ConstructorInterpolatedStringHandler(int literalLength, int formattedCount, A clas, out bool handlerIsValid)
{
if (clas.Name == "Mykyta")
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s)
{
handler.AppendLiteral(s);
}
public void AppendFormatted<T>(T t)
{
handler.AppendFormatted(t);
}
public string ToStringAndClear()
{
return handler.ToStringAndClear();
}
public override string ToString()
{
return handler.ToStringAndClear();
}
}
// see more here: https://sergeyteplyakov.github.io/Blog/c%2310/2021/11/08/Dissecing-Interpolated-Strings-Improvements-In-CSharp-10.html
}
using System.Runtime.CompilerServices;
using System;
public static class Program
{
public static void Main()
{
var mh = new MultiHandlers();
mh.Print($"firstHandlerText", $"secondHandlerText");
}
public class MultiHandlers
{
public string Name = "Mykyta";
public void Print(
[InterpolatedStringHandlerArgument("")] InterpolatedStringHandler handler,
[InterpolatedStringHandlerArgument("", "handler")] DependentInterpolatedStringHandler dependentHandler)
{
Console.WriteLine(dependentHandler.ToStringAndClear());
}
}
// The handler that will actually "build" the interpolated string"
[InterpolatedStringHandler]
public ref struct DependentInterpolatedStringHandler
{
private InterpolatedStringHandler handler;
public DependentInterpolatedStringHandler(int literalLength, int formattedCount, MultiHandlers mh, InterpolatedStringHandler handler, out bool handlerIsValid)
{
this.handler = handler;
if (mh.Name != "Mykyta")
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
}
public void AppendLiteral(string s)
{
handler.AppendLiteral(s);
}
public void AppendFormatted<T>(T t)
{
handler.AppendFormatted(t);
}
public string ToStringAndClear()
{
return handler.ToStringAndClear();
}
public override string ToString()
{
return this.ToStringAndClear();
}
}
[InterpolatedStringHandler]
public ref struct InterpolatedStringHandler
{
private DefaultInterpolatedStringHandler handler;
public InterpolatedStringHandler(int literalLength, int formattedCount, MultiHandlers mh, out bool handlerIsValid)
{
handler = default;
if (mh.Name != "Mykyta")
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s)
{
handler.AppendLiteral(s);
}
public void AppendFormatted<T>(T t)
{
handler.AppendFormatted(t);
}
public string ToStringAndClear()
{
return handler.ToStringAndClear();
}
public override string ToString()
{
return this.ToStringAndClear();
}
}
// see more here: https://sergeyteplyakov.github.io/Blog/c%2310/2021/11/08/Dissecing-Interpolated-Strings-Improvements-In-CSharp-10.html
}
using System.Runtime.CompilerServices;
using System;
public static class Program
{
public static void Main()
{
Logger logger = GetLogger(LogLevel.Error);
var name = "Fred Silberberg";
logger.Log(LogLevel.Info, $"{name} will never be printed because info is < error!");
}
public static Logger GetLogger(LogLevel level)
{
return new Logger { EnabledLevel = level };
}
public enum LogLevel
{
Debug = 0,
Info,
Warning,
Error,
Fatal
}
public class Logger
{
// Initialization code omitted
public LogLevel EnabledLevel;
public void Log(LogLevel level, [InterpolatedStringHandlerArgument("", "level")]LoggerInterpolatedStringHandler handler)
{
if (EnabledLevel <= level) Console.WriteLine(handler.ToString());
}
}
// The handler that will actually "build" the interpolated string"
[InterpolatedStringHandler]
public ref struct LoggerInterpolatedStringHandler
{
private DefaultInterpolatedStringHandler handler;
public LoggerInterpolatedStringHandler(int literalLength, int formattedCount, Logger logger, LogLevel level, out bool handlerIsValid)
{
handler = default;
if (logger.EnabledLevel > level)
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s)
{
handler.AppendLiteral(s);
}
public void AppendFormatted<T>(T t)
{
handler.AppendFormatted(t);
}
public string ToStringAndClear()
{
return handler.ToStringAndClear();
}
public override string ToString()
{
return handler.ToStringAndClear();
}
}
// see more here: https://sergeyteplyakov.github.io/Blog/c%2310/2021/11/08/Dissecing-Interpolated-Strings-Improvements-In-CSharp-10.html
}
using System.Runtime.CompilerServices;
using System;
public static class Program
{
public static void Main()
{
var name = "jslkfjdl";
var mh = new MultiHandlers();
mh.Print($"lo{name}" + $"2", $"{name}");
}
public class MultiHandlers
{
public string Name = "Mykyta";
public void Print(
[InterpolatedStringHandlerArgument("")] MultiInterpolatedStringHandler handler1,
[InterpolatedStringHandlerArgument("")] MultiInterpolatedStringHandler handler2)
{
Console.WriteLine(handler1.ToStringAndClear());
Console.WriteLine(handler2.ToStringAndClear());
}
}
// The handler that will actually "build" the interpolated string"
[InterpolatedStringHandler]
public ref struct MultiInterpolatedStringHandler
{
private DefaultInterpolatedStringHandler handler;
public MultiInterpolatedStringHandler(int literalLength, int formattedCount, MultiHandlers mh, out bool handlerIsValid)
{
handler = default;
if (mh.Name != "Mykyta")
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s)
{
handler.AppendLiteral(s);
}
public void AppendFormatted<T>(T t)
{
handler.AppendFormatted(t);
}
public string ToStringAndClear()
{
return handler.ToStringAndClear();
}
public override string ToString()
{
return handler.ToStringAndClear();
}
}
// see more here: https://sergeyteplyakov.github.io/Blog/c%2310/2021/11/08/Dissecing-Interpolated-Strings-Improvements-In-CSharp-10.html
}
using System.Runtime.CompilerServices;
using System.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public static class Program
{
public static void Main()
{
var logger = new Logger() { EnabledLevel = LogLevel.Warning };
var time = DateTime.Now;
logger.LogMessage(LogLevel.Error, $"Error Level. CurrentTime: {time}. This is an error. It will be printed." + $"1");
}
public enum LogLevel
{
Off,
Critical,
Error,
Warning,
Information,
Trace
}
public class Logger
{
public LogLevel EnabledLevel { get; init; } = LogLevel.Error;
public void LogMessage(LogLevel level, string msg)
{
if (EnabledLevel < level) return;
Console.WriteLine(msg);
}
public void LogMessage(LogLevel level, NoArgsAttrInterpolatedStringHandler builder)
{
if (EnabledLevel < level) return;
Console.WriteLine(builder.GetFormattedText());
}
}
/////////////////////////////////////////////////
//// Interpolated String Handler pattern
/////////////////////////////////////////////////
[InterpolatedStringHandler]
public ref struct NoArgsAttrInterpolatedStringHandler
{
// Storage for the built-up string
StringBuilder builder;
public NoArgsAttrInterpolatedStringHandler(int literalLength, int formattedCount)
{
builder = new StringBuilder(literalLength);
Console.WriteLine($"\tliteral length: {literalLength}, formattedCount: {formattedCount}");
}
public void AppendLiteral(string s)
{
Console.WriteLine($"\tAppendLiteral called: {{{s}}}");
builder.Append(s);
Console.WriteLine($"\tAppended the literal string");
}
public void AppendFormatted<T>(T t)
{
Console.WriteLine($"\tAppendFormatted called: {{{t}}} is of type {typeof(T)}");
builder.Append(t?.ToString());
Console.WriteLine($"\tAppended the formatted object");
}
internal string GetFormattedText() => builder.ToString();
}
// see more here: https://sergeyteplyakov.github.io/Blog/c%2310/2021/11/08/Dissecing-Interpolated-Strings-Improvements-In-CSharp-10.html
}
using System.Runtime.CompilerServices;
using System;
public static class Program
{
public static void Main()
{
const string i = "1";
var logger = new Logger() { EnabledLevel = LogLevel.Warning };
logger.Log(LogLevel.Error, $"{i + "1" + $"{i + "1" + $"{i}"}"}" + $"2"); // 111112
logger.Log(LogLevel.Error, $"{@"5"}jkl{(i + "2")}1{i + "9"}"); // 5jkl12119
logger.Log(LogLevel.Error, $"{"1"}"); // 1
logger.Log(LogLevel.Error, $"{1}"); // $"{1}" (non-const since it's int)
}
static Logger GetLogger(LogLevel level)
{
return new Logger { EnabledLevel = level };
}
public enum LogLevel
{
Debug = 0,
Info,
Warning,
Error,
Fatal
}
public class Logger
{
// Initialization code omitted
public LogLevel EnabledLevel;
public void Log(LogLevel level, [InterpolatedStringHandlerArgument("", "level")]LoggerInterpolatedStringHandler handler)
{
if (EnabledLevel <= level) Console.WriteLine(handler.ToString());
}
}
/////////////////////////////////////////////////
//// Interpolated String Handler pattern
/////////////////////////////////////////////////
// The handler that will actually "build" the interpolated string"
[InterpolatedStringHandler]
public ref struct LoggerInterpolatedStringHandler
{
private DefaultInterpolatedStringHandler handler;
public LoggerInterpolatedStringHandler(int literalLength, int formattedCount, Logger logger, LogLevel level, out bool handlerIsValid)
{
handler = default;
if (logger.EnabledLevel > level)
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s)
{
handler.AppendLiteral(s);
}
public void AppendFormatted<T>(T t)
{
handler.AppendFormatted(t);
}
public string ToStringAndClear()
{
return handler.ToStringAndClear();
}
public override string ToString()
{
return handler.ToStringAndClear();
}
}
// see more here: https://sergeyteplyakov.github.io/Blog/c%2310/2021/11/08/Dissecing-Interpolated-Strings-Improvements-In-CSharp-10.html
}
using System.Runtime.CompilerServices;
using System.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public static class Program
{
public static void Main()
{
var logger = new Logger() { EnabledLevel = LogLevel.Warning };
var time = DateTime.Now;
logger.LogMessage(LogLevel.Error, $"Error Level. CurrentTime: {time}. This is an error. It will be printed." + $"1");
}
public enum LogLevel
{
Off,
Critical,
Error,
Warning,
Information,
Trace
}
public class Logger
{
public LogLevel EnabledLevel { get; init; } = LogLevel.Error;
public void LogMessage(LogLevel level, string msg)
{
if (EnabledLevel < level) return;
Console.WriteLine(msg);
}
public void LogMessage(LogLevel level, ref RefParamInterpolatedStringHandler builder)
{
if (EnabledLevel < level) return;
Console.WriteLine(builder.GetFormattedText());
}
}
/////////////////////////////////////////////////
//// Interpolated String Handler pattern
/////////////////////////////////////////////////
[InterpolatedStringHandler]
public ref struct RefParamInterpolatedStringHandler
{
// Storage for the built-up string
StringBuilder builder;
public RefParamInterpolatedStringHandler(int literalLength, int formattedCount)
{
builder = new StringBuilder(literalLength);
Console.WriteLine($"\tliteral length: {literalLength}, formattedCount: {formattedCount}");
}
public void AppendLiteral(string s)
{
Console.WriteLine($"\tAppendLiteral called: {{{s}}}");
builder.Append(s);
Console.WriteLine($"\tAppended the literal string");
}
public void AppendFormatted<T>(T t)
{
Console.WriteLine($"\tAppendFormatted called: {{{t}}} is of type {typeof(T)}");
builder.Append(t?.ToString());
Console.WriteLine($"\tAppended the formatted object");
}
internal string GetFormattedText() => builder.ToString();
}
// see more here: https://sergeyteplyakov.github.io/Blog/c%2310/2021/11/08/Dissecing-Interpolated-Strings-Improvements-In-CSharp-10.html
}
using System.Runtime.CompilerServices;
using System;
/////////////////////////////////////////////////
//// Usage
/////////////////////////////////////////////////
var s = new Struct();
s.Print($"Struct handler {"text"}");
/////////////////////////////////////////////////using System.Runtime.CompilerServices;
using System;
public static class Program
{
public static void Main()
{
var s = new Struct();
s.Print($"Struct handler {"text"}");
}
public struct Struct
{
public string Name = "Mykyta";
public Struct() {}
public void Print([InterpolatedStringHandlerArgument("")] StructInterpolatedStringHandler handler)
{
Console.WriteLine(handler.ToStringAndClear());
}
}
/////////////////////////////////////////////////
//// Interpolated String Handler pattern
/////////////////////////////////////////////////
[InterpolatedStringHandler]
public ref struct StructInterpolatedStringHandler
{
private DefaultInterpolatedStringHandler handler;
public StructInterpolatedStringHandler(int literalLength, int formattedCount, Struct s, out bool handlerIsValid)
{
handler = default;
if (s.Name != "Mykyta")
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s)
{
handler.AppendLiteral(s);
}
public void AppendFormatted<T>(T t)
{
handler.AppendFormatted(t);
}
public string ToStringAndClear()
{
return handler.ToStringAndClear();
}
public override string ToString()
{
return this.ToStringAndClear();
}
}
// see more here: https://sergeyteplyakov.github.io/Blog/c%2310/2021/11/08/Dissecing-Interpolated-Strings-Improvements-In-CSharp-10.html
}
//// Struct
/////////////////////////////////////////////////
public struct Struct
{
public string Name = "Mykyta";
public Struct() {}
public void Print([InterpolatedStringHandlerArgument("")] StructInterpolatedStringHandler handler)
{
Console.WriteLine(handler.ToStringAndClear());
}
}
/////////////////////////////////////////////////
//// Interpolated String Handler pattern
/////////////////////////////////////////////////
[InterpolatedStringHandler]
public ref struct StructInterpolatedStringHandler
{
private DefaultInterpolatedStringHandler handler;
public StructInterpolatedStringHandler(int literalLength, int formattedCount, Struct s, out bool handlerIsValid)
{
handler = default;
if (s.Name != "Mykyta")
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s)
{
handler.AppendLiteral(s);
}
public void AppendFormatted<T>(T t)
{
handler.AppendFormatted(t);
}
public string ToStringAndClear()
{
return handler.ToStringAndClear();
}
public override string ToString()
{
return this.ToStringAndClear();
}
}
// see more here: https://sergeyteplyakov.github.io/Blog/c%2310/2021/11/08/Dissecing-Interpolated-Strings-Improvements-In-CSharp-10.html
using System.Runtime.CompilerServices;
using System;
public static class Program
{
public static void Main()
{
var name = "jslkfjdl";
var gen = new Generic<int>() { field = 5 };
gen.Print($"lo{name}" + $"2");
}
public class Generic<T>
{
public T field;
public void Print(
[InterpolatedStringHandlerArgument("")] SubstitutedGenericInterpolatedStringHandler<T> handler)
{
Console.WriteLine(handler.ToStringAndClear());
}
}
// The handler that will actually "build" the interpolated string"
[InterpolatedStringHandler]
public ref struct SubstitutedGenericInterpolatedStringHandler<T>
{
private DefaultInterpolatedStringHandler handler;
public SubstitutedGenericInterpolatedStringHandler(int literalLength, int formattedCount, Generic<T> gen, out bool handlerIsValid)
{
handler = default;
if (gen.field.Equals(default(T)))
{
handlerIsValid = false;
return;
}
handlerIsValid = true;
handler = new(literalLength, formattedCount);
}
public void AppendLiteral(string s)
{
handler.AppendLiteral(s);
}
public void AppendFormatted<T1>(T1 t)
{
handler.AppendFormatted(t);
}
public string ToStringAndClear()
{
return handler.ToStringAndClear();
}
public override string ToString()
{
return handler.ToStringAndClear();
}
}
// see more here: https://sergeyteplyakov.github.io/Blog/c%2310/2021/11/08/Dissecing-Interpolated-Strings-Improvements-In-CSharp-10.html
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment