.NET 7μ΄ λ―Έλ¦¬λ³΄κΈ° 릴리μ€κ° μ’ λ£λλ©΄μ C# 11 κΈ°λ₯μ΄ νμ λμμ΅λλ€. μ΄μ λ°λΌ C# 11 κΈ°λ₯μ λν΄ μ 리ν©λλ€.
C# 11 κΈ°λ₯ λͺ©λ‘
μλ‘κ² μΆκ°λ C# 11μ κΈ°λ₯μ λ€μκ³Ό κ°μ΅λλ€.
- File-local Types (νμΌ λ‘컬 νμ )
- ref fields (ref νλ)
- Required members (required λ©€λ²)
- DIM for Static Members (μ μ μΆμ λ©€λ²)
- Numberic IntPtr (μ«μ IntPtr)
- Unsigned right shift operator (λΆνΈ μλ μ€λ₯Έμͺ½ μννΈ μ°μ°μ)
- Utf8 String Literals (UTF8 λ¬Έμμ΄ λ¦¬ν°λ΄)
- Pattern matching on
ReadOnlySpan<char>
(ReadOnlySpan<char>
μ ν¨ν΄ 맀μΉ) - Checked Operators (checked μ°μ°μ)
- auto-default structs (μλ κΈ°λ³Έ ꡬ쑰체)
- Newlines in interpolations (보κ°μ κ°ν)
- List patterns (λͺ©λ‘ ν¨ν΄)
- Raw string literals (μμ λ¬Έμμ΄ λ¦¬ν°λ΄)
- Cache delegates for static method group (μ μ λ©μλ κ·Έλ£Ήμ λν μΊμ λ리μ)
- nameof(parameter)
- Relaxing Shift Operator (μννΈ μ°μ°μμ μ μ½ μν)
- Generic attributes (μ λ€λ¦ νΉμ±)
C# 11 κΈ°λ₯
νμΌ λ‘컬 νμ (File-local Types)
νμΌ λ΄μμλ§ μ ν¨ν νμ μ μ μν μ μμ΅λλ€.
// FileLocalType.cs
file class FileLocalType
{
}
// Program.cs
var s = new FileLocalType();
// μ€λ₯ CS0246 'FileLocalType' νμ λλ λ€μμ€νμ΄μ€ μ΄λ¦μ μ°Ύμ μ μμ΅λλ€. using μ§μλ¬Έ λλ μ΄μ
λΈλ¦¬ μ°Έμ‘°κ° μλμ§ νμΈνμΈμ.
ref νλ (ref fields)
Span<T>
μ ref νλ
_reference
μ²λΌ
public readonly ref struct Span<T>
{
/// <summary>A byref or a native ptr.</summary>
internal readonly ref T _reference;
/// <summary>The number of elements this Span contains.</summary>
private readonly int _length;
...
μ΄μ μΌλ° κ°λ°μλ ref νλ
λ₯Ό λ§λ€ μ μκ² λμμ΅λλ€.
ref νλλ μ€ν 곡κ°μλ§ μ‘΄μ¬ν μ μμΌλ―λ‘
ref struct
μμλ§ μ¬μ©ν μ μμ΅λλ€.
ref struct Vector2D
{
public ref int X;
public ref int Y;
}
required λ©€λ² (Required members)
μ΄μ required
ν€μλλ‘ νμ λ©€λ²λ₯Ό λ§λ€ μ μμ΅λλ€.
public class User
{
public required string Name { get; init; }
public required int Age { get; init; }
}
var user1 = new User();
// μ€λ₯ CS9035 νμ ꡬμ±μ 'User.Age'μ(λ) κ°μ²΄ μ΄λμ
λΌμ΄μ λλ νΉμ± μμ±μμμ μ€μ ν΄μΌ ν©λλ€.
// μ€λ₯ CS9035 νμ ꡬμ±μ 'User.Name'μ(λ) κ°μ²΄ μ΄λμ
λΌμ΄μ λλ νΉμ± μμ±μμμ μ€μ ν΄μΌ ν©λλ€.
var user2 = new User
{
Name = "dimohy",
Age = 45
};
μ μ μΆμ λ©€λ² (DIM for Static Members)
μ΄μ μ μ μμ± λ° λ©μλ μμ μΈν°νμ΄μ€λ‘ ꡬνμ κ°μ ν μ μμ΅λλ€.
public interface IValue<T>
{
static abstract T Empty { get; }
}
public class NumValue : IValue<NumValue>
{
public static NumValue Empty { get; } = new(0);
private int _value;
public NumValue(int value) => _value = value;
}
μ΄λ₯Ό ν΅ν΄ μ΄μ μ λ€λ¦ νμ μ μ½ μ‘°κ±΄ where
λ₯Ό μ΄μ©ν΄ μ μ μμ± λ° λ©μλλ₯Ό μ¬μ©νλ κΈ°λ₯μ ꡬνν μ μμ΅λλ€.
var emptyValue = GetEmptyValue(new NumValue(100));
T GetEmptyValue<T>(T value) where T : IValue<T>
{
return T.Empty;
}
μ«μ IntPtr (Numberic IntPtr)
IntPtr/UIntPtr
κ³Ό νλ«νΌ μμ‘΄μ μΈ μ μ νμ
nint / nuintμ΄
νλ«νΌ μμ‘΄μ μΈ λμΌν μ μν λ°μ΄ν° κ°μμλ λΆκ΅¬νκ³ λ€λ₯΄κ² μ·¨κΈλμ΄ μ μνμμ μ 곡νλ μ°μ°μ μ 곡νμ§ μμμ΅λλ€.
μ΄μ λ νμ μ λμΌν νμ μΌλ‘ μ²λ¦¬λ©λλ€. μ¦, nintμ nuintλ IntPtrκ³Ό UIntPtrμ aliasμ΄κ³ λμΌν νμ μ΄ λ©λλ€.
λΆνΈ μλ μ€λ₯Έμͺ½ μννΈ μ°μ°μ (Unsigned right shift operator)
Javaμλ μ‘΄μ¬νλ uinsiged right shift
μ°μ°μλ₯Ό μ΄μ C#μμλ μ 곡ν©λλ€.
int n = -2020987651; // 0b10000111100010100010110011111101
Console.WriteLine($"[n] \t\t {Convert.ToString(n, 2).PadLeft(32, '0')}");
Console.WriteLine($"[n] >>> 4 ==> \t {Convert.ToString(n >>> 4, 2).PadLeft(32, '0')}");
Console.WriteLine($"[n] >> 4 ==> \t {Convert.ToString(n >> 4, 2).PadLeft(32, '0')}");
[n] 10000111100010100010110011111101
[n] >>> 4 ==> 00001000011110001010001011001111
[n] >> 4 ==> 11111000011110001010001011001111
UTF8 λ¬Έμμ΄ λ¦¬ν°λ΄ (Utf8 String Literals)
μ΄μ u8
μ λ―Έμ¬λ₯Ό ν΅ν΄ UTF8 λ¬Έμμ΄ λ¦¬ν°λ΄μ λ§λ€ μ μμ΅λλ€.
ReadOnlySpan<byte> utf8Text = "λλͺ¨μ΄"u8; // λλ
var utf8Text = "λλͺ¨μ΄"u8;
UTF8 λ¬Έμμ΄ λ¦¬ν°λ΄μ ReadOnlySpan<byte>
νμ
μ΄λ―λ‘ μΌλ° λ¬Έμμ΄ λ¦¬ν°λ΄ μ²λΌ μμλ‘ μ·¨κΈλμ§λ μμ΅λλ€. λν ReadOnlySpan<byte>
νμ
μ΄ μ€νμλ§ μ‘΄μ¬ν μ μμΌλ―λ‘ λΉλκΈ° λ©μλμμ μ¬μ©ν μ μλ μ μ½μ΄ μ‘΄μ¬ν©λλ€.
ReadOnlySpan<char>
μ ν¨ν΄ λ§€μΉ (Pattern matching on ReadOnlySpan<char>
)
μ΄μ ν¨ν΄ 맀μΉμμ ReadOnlySpan<char>
λ₯Ό λ¬Έμμ΄κ³Ό 맀μΉμν¬ μ μμ΅λλ€.
ReadOnlySpan<char> text = "λλͺ¨μ΄";
switch (text)
{
case "λλͺ¨μ΄":
break;
default:
break;
}
checked μ°μ°μ (Checked Operators)
μ΄μ overflow μ μ΄μ νμν checked/unchecked
λμμ μ§μ μ²λ¦¬ν μ μκ² λ©λλ€.
// μΆμ² - μ±νμ λ·λ· μ΄μΌκΈ°
public static Int3 operator checked ++(Int3 lhs)
{
if (lhs.value + 1 > 8388607)
{
throw new OverflowException((lhs.value + 1).ToString());
}
return new Int3(lhs.value + 1);
}
public static Int3 operator ++(Int3 lhs) => new Int3(lhs.value + 1);
μλ κΈ°λ³Έ ꡬ쑰체 (auto-default structs)
μ΄μ ꡬ쑰체μμ νλλ₯Ό μ΄κΈ°ν νμ§ μμλ μλμΌλ‘ default
μΌλ‘ μ΄κΈ°ν λ©λλ€.
// C# 11 μ΄μ μλ μ΄κΈ°ν κ΄λ ¨ μ€λ₯ λ°μ
public struct S
{
public int x, y;
public S()
{
}
}
보κ°μ κ°ν (Newlines in interpolations)
μ΄μ 보κ°μμ κ°νμ΄ κ°λ₯ν©λλ€.
var v = $"Count is\t: { this.Is.A.Really()
.That.I.Should(
be + able)[
to.Wrap()] }.";
λͺ©λ‘ ν¨ν΄ (List patterns)
μ΄μ λͺ©λ‘ ν¨ν΄μ΄ μ§μλ©λλ€.
int[] arr = { 1, 2, 3, 4, 5, 6 };
var result = arr switch
{
//[1, .., 6] => 1,
[1, .., 5, _] => 2,
_ => 0
};
Console.WriteLine(result);
μμ λ¬Έμμ΄ λ¦¬ν°λ΄ (Raw string literals)
μ΄μ μμ λ¬Έμμ΄ λ¦¬ν°λ΄μ μ¬μ©ν μ μμ΅λλ€.
var rawText = """
Line 1, value 1
Line 2, value 2
Line 3, value 3
""";
Console.WriteLine(rawText);
λ§μ§λ§ λ«λ """
μμΉμ λ§κ² λ¬Έμμ΄λ‘ μ λμ
λ©λλ€.
Line 1, value 1
Line 2, value 2
Line 3, value 3
λ§μ½ λ¬Έμμ΄ μμ """
κ° ν¬ν¨λμ΄ μμ κ²½μ°, μ΄κ³ λ«λ ν°λ°μ΄νλ₯Ό """"
λ‘ ν μ μμ΅λλ€.
var rawText = """"
Line 1, value 1
Line 2, value 2
Line 3, value 3
"""Text"""
"""";
Console.WriteLine(rawText);
Line 1, value 1
Line 2, value 2
Line 3, value 3
"""Text"""
λν λ¬Έμμ΄ λ³΄κ°λ μ¬μ©ν μ μμ΅λλ€.
var num = 1;
var rawText = $""""
Line 1, value {num}
Line 2, value {num + 1}
Line 3, value {num + 2}
"""Text"""
"""";
Console.WriteLine(rawText);
Line 1, value 1
Line 2, value 2
Line 3, value 3
"""Text"""
κ·Έλ°λ° JSON λ¬Έμμ΄ μ²λΌ λ¬Έμμ΄μ {
λλ }
μ΄ μμ κ²½μ° $
λμ $$
μ, {value}
λμ {{value}}
μΌλ‘ μ¬μ©ν μ μμ΅λλ€.
var num = 1;
var rawText = $$""""
{
Line 1, value {{num}}
Line 2, value {{num + 1}}
Line 3, value {{num + 2}}
}
"""Text"""
"""";
Console.WriteLine(rawText);
{
Line 1, value 1
Line 2, value 2
Line 3, value 3
}
"""Text"""
μ μ λ©μλ κ·Έλ£Ήμ λν μΊμ λ리μ (Cache delegates for static method group)
ν΄λ‘μ κ° μλ μ μ λ©μλ κ·Έλ£Ήμ λν΄μ C# 11 μ΄μ μλ νΈμΆν λλ§λ€ λ리μμ μ μΈμ€ν΄μ€λ₯Ό λ§λ€μμ΅λλ€.
void Demo(Func<string> action) { }
string GetString() => "";
```csharp
// C# code
Demo(GetString); // -> Demo(new Func<string>(GetString));
μ΄μ ν΄λ‘μ κ° μμΌλ©΄ μ»΄νμΌλ¬λ λ리μλ₯Ό μΊμνκ³ κ° νΈμΆμμ μ¬μ¬μ© ν©λλ€.
nameof(parameter)
μ΄μ 맀κ°λ³μμ μ΄λ¦ μμ nameof(parameter)
ννλ‘ μ¬μ©ν μ μκ² λμμ΅λλ€.
Assert(1 == 1);
Assert("A" == "B");
void Assert(bool condition, [CallerArgumentExpression(nameof(condition))] string? message = default)
{
Console.WriteLine(nameof(condition));
Console.WriteLine(message);
}
condition
1 == 1
condition
"A" == "B"
μννΈ μ°μ°μμ μ μ½ μν (Relaxing Shift Operator)
μ΄μ μννΈ μ°μ°μμ νμ μνλ‘ λ€λ₯Έ νμ μ μ°μ°μ 맀κ°λ³μλ‘ λ°μ μ μκ² λμμ΅λλ€.
// μΆμ² - μ±νμ λ·λ· μ΄μΌκΈ°
C c = new C();
C d = c << 5.8f;
class C
{
public static C operator << (C c, float o)
{
Console.WriteLine("shift operator called with " + o);
return c;
}
}
μ λ€λ¦ νΉμ± (Generic attributes)
μ΄μ νΉμ± νμ μ μ λ€λ¦μ μ¬μ©ν μ μκ² λμμ΅λλ€.
class ValueAttribute<TValue> : Attribute
where TValue : struct
{
public TValue V { get; set; }
}
[Value<int>(V = 10)]
class TestClass
{
}
μ°Έκ³ μλ£
μ’ λ μμΈν λ΄μ©μ μλμ λ¬Έμλ₯Ό νμΈνμΈμ.
- μ±νμ λ·λ· μ΄μΌκΈ°
- C# 11 - λ©μλ λ§€κ° λ³μμ λν nameof μ§μ
- C# 11 - νμΌ λ²μ λ΄μμ μ ν¨ν νμ μ μ (File-local types)
- C# 11 - Span νμ
μ λν ν¨ν΄ λ§€μΉ (Pattern matching on
ReadOnlySpan<char>
) - C# 11 - λͺ©λ‘ ν¨ν΄(List patterns)
- C# 11 - IntPtr/UIntPtrκ³Ό nint/nuintμ ν΅ν©
- C# 11 - μλ‘μ΄ μ°μ°μ β>>>β (Unsigned Right Shift)
- C# 11 - shift μ°μ°μ μ¬μ μμ λν μ μ½ μν (Relaxing Shift Operator)
- C# 11 - μ¬μ©μ μ μ checked μ°μ°μ
- C# 11 - UTF-8 λ¬Έμμ΄ λ¦¬ν°λ΄
- C# 11 - λ¬Έμμ΄ λ³΄κ° κ°μ 2κ°μ§
- C# 11 - μμ λ¬Έμμ΄ λ¦¬ν°λ΄(raw string literals)
- C# 11 - ref structμ ref νλλ₯Ό νμ©
- C# 11 - μ λ€λ¦ νμ μ νΉμ± μ μ©
- C# 11 - μΈν°νμ΄μ€ λ΄μ μ μ μΆμ λ©μλ μ μ κ°λ₯ (DIM for Static Members)
- Performance: Lambda Expressions, Method Groups, and delegate caching | GΓ©rald BarrΓ© | MEZIANTOUβS BLOG