Intro
In C# 7 and C# 8, "switch" got some new features.
In this time, I will try using "switch".
Environments
- .NET 5.0.100
Before C# 7 (Constant Patterns)
Program.cs
class Program
{
static void Main(string[] args)
{
int id = 1;
switch(id)
{
case 0:
Console.WriteLine("Id was 0");
break;
case 1:
Console.WriteLine("Id was 1");
break;
default:
Console.WriteLine("Not found");
break;
}
}
}
Only constant values can be used.
New Patterns
Type Patterns
After C# 7, I can use type.
In type pattern, after checking if a target object can be converted, converted instance will be created.
RecordSample.cs
public record RecordSample(int Id, string Name);
Program.cs
static void Main(string[] args)
{
RecordSample r = new (3, "Hello");
Play((object)r);
}
private static void Play(object target)
{
switch(target)
{
case RecordSample r:
Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
break;
default:
Console.WriteLine("Not found");
break;
}
}
Result
Record Id: 3 Name: Hello
Tuple Patterns
Program.cs
static void Main(string[] args)
{
(int Id, string Name) t = (0, "Hello");
Play((object)t);
}
private static void Play(object target)
{
switch(target)
{
case RecordSample r:
Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
break;
case (0, "Hello"):
Console.WriteLine("Tuple");
break;
default:
Console.WriteLine("Not found");
break;
}
}
Result
Tuple
Property Patterns
Program.cs
static void Main(string[] args)
{
var r = new RecordSample(1, "Hello");
Play((object)r);
}
private static void Play(object target)
{
switch(target)
{
case RecordSample { Id: 1} r:
Console.WriteLine($"Property pattern Id: {r.Id} Name: {r.Name}");
break;
case RecordSample r:
Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
break;
default:
Console.WriteLine("Not found");
break;
}
}
Result
Property pattern Id: 1 Name: Hello
I also can use some more patterns(ex. Positional Patterns).
when
In new Patterns(ex. Type Patterns), I can separate into more specific conditions.
Program.cs
static void Main(string[] args)
{
var r = new RecordSample(1, "Hello");
Play((object)r);
}
private static void Play(object target)
{
switch(target)
{
case RecordSample r when r.Id < 0:
Console.WriteLine($"Record1 Id: {r.Id} Name: {r.Name}");
break;
case RecordSample r when r.Id >= 1:
Console.WriteLine($"Record2 Id: {r.Id} Name: {r.Name}");
break;
case RecordSample r:
Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
break;
default:
Console.WriteLine("Not found");
break;
}
}
Result
Record2 Id: 1 Name: Hello
switch expression
In C# 8, "switch expression" was added.
I can refactor like below.
Before
Program.cs
static void Main(string[] args)
{
int id = 1;
string message = GetMessage(id);
Console.WriteLine(message);
}
private static string GetMessage(int id)
{
switch(id)
{
case 0:
return "ID was 0";
case 1:
return "ID was 1";
default:
return "Other";
}
}
Result
ID was 1
After
Program.cs
static void Main(string[] args)
{
int id = 1;
string message = id switch
{
0 => "ID was 0",
1 => "ID was 1",
_ => "Other"
};
Console.WriteLine(message);
}
Result
ID was 1
I can use same patterns as the switch statement.
Resources
- Pattern Matching - C# Guide | Microsoft Docs
- C# 8.0 - Pattern Matching in C# 8.0 | Microsoft Docs
- C# switch statement | Microsoft Docs
- switch expression - C# reference | Microsoft Docs
- Do more with patterns in C# 8.0 | .NET Blog
- Programming C# 8.0
- https://ufcpp.net/study/csharp/datatype/patterns/
- C# 8.0 パターン マッチング | ++C++; // 未確認飛行 C ブログ
How many instances are created?
Question
For example, when I execute this code, how many instances are created?
Program.cs
static void Main(string[] args)
{
var r = new RecordSample(0, "Hello");
Play((object)r);
}
private static void Play(object target)
{
switch(target)
{
case RecordSample r when r.Id < 0:
Console.WriteLine($"Record1 Id: {r.Id} Name: {r.Name}");
break;
case RecordSample r when r.Id >= 1:
Console.WriteLine($"Record2 Id: {r.Id} Name: {r.Name}");
break;
case RecordSample r:
// Execute here
Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
break;
default:
Console.WriteLine("Not found");
break;
}
}
Answer
Only one instance is created.
Decompile
I decompile this code by ILSpy(https://marketplace.visualstudio.com/items?itemName=icsharpcode.ilspy-vscode).
private static void Play(object target)
{
RecordSample recordSample = target as RecordSample;
if ((object)recordSample != null)
{
if (recordSample.Id < 0)
{
Console.WriteLine($"Record1 Id: {recordSample.Id} Name: {recordSample.Name}");
return;
}
RecordSample recordSample2 = recordSample;
if (recordSample2.Id >= 1)
{
Console.WriteLine($"Record2 Id: {recordSample2.Id} Name: {recordSample2.Name}");
return;
}
RecordSample recordSample3 = recordSample;
Console.WriteLine($"Record Id: {recordSample3.Id} Name: {recordSample3.Name}");
}
else
{
Console.WriteLine("Not found");
}
}
- A instance is created by "as RecordSample"
- If it isn't null, use the if statement to perform the operation under the condition of the when clause.
So only one instance is created.
Convert an object like TypeScript
In TypeScript, I can convert if an instance has same property as RecordSample class.
record-sample.ts
export class RecordSample {
public id: number = -1;
public name: string = "";
}
program.ts
import { RecordSample } from "./record-sample";
export function main(){
const s = {
id: 1,
name: "Hello"
};
const r: RecordSample = s; // <- OK
}
I also want to convert like this in C#.
First, I add a method to convert.
RecordSample.cs
public record RecordSample
{
public int Id { get; init; }
public string Name { get; init; } = "";
public RecordSample(int id, string name)
{
Id = id;
Name = name;
}
public static bool TryParse(object original, out RecordSample? result)
{
result = null;
var type = original.GetType();
var idValue = type.GetProperty("Id")?.GetValue(original)?.ToString();
var nameValue = type.GetProperty("Name")?.GetValue(original)?.ToString();
if(idValue == null || nameValue == null)
{
return false;
}
if(int.TryParse(idValue.ToString(), out var id) == false)
{
return false;
}
result = new RecordSample(id, nameValue);
return true;
}
}
And I add this into the switch statement.
private static void Play(object target)
{
switch(target)
{
case RecordSample r:
Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
break;
case var o when RecordSample.TryParse(o, out var r):
Console.WriteLine($"Property Id: {r!.Id} Name: {r!.Name}");
break;
default:
Console.WriteLine("Not found");
break;
}
}
"var" in switch statements can catch all conditions.
And check target's properties by when clause.
Program.cs
static void Main(string[] args)
{
var r = new {
Id = 0,
Name = "Hello"
};
Play((object)r);
}
private static void Play(object target)
{
switch(target)
{
case RecordSample r:
Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
break;
case var o when RecordSample.TryParse(o, out var r):
Console.WriteLine($"Property Id: {r!.Id} Name: {r!.Name}");
break;
default:
Console.WriteLine("Not found");
break;
}
}
Result
Property Id: 0 Name: Hello
Top comments (0)