diff --git a/csharp-methods/VirtualMethodsInCSharp/Benchmarks/Benchmarks.csproj b/csharp-methods/VirtualMethodsInCSharp/Benchmarks/Benchmarks.csproj
new file mode 100644
index 0000000000..62be4f867f
--- /dev/null
+++ b/csharp-methods/VirtualMethodsInCSharp/Benchmarks/Benchmarks.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/csharp-methods/VirtualMethodsInCSharp/Benchmarks/Program.cs b/csharp-methods/VirtualMethodsInCSharp/Benchmarks/Program.cs
new file mode 100644
index 0000000000..9934f132e6
--- /dev/null
+++ b/csharp-methods/VirtualMethodsInCSharp/Benchmarks/Program.cs
@@ -0,0 +1,4 @@
+using BenchmarkDotNet.Running;
+using Benchmarks;
+
+BenchmarkRunner.Run();
diff --git a/csharp-methods/VirtualMethodsInCSharp/Benchmarks/Shapes.cs b/csharp-methods/VirtualMethodsInCSharp/Benchmarks/Shapes.cs
new file mode 100644
index 0000000000..35535fefe4
--- /dev/null
+++ b/csharp-methods/VirtualMethodsInCSharp/Benchmarks/Shapes.cs
@@ -0,0 +1,36 @@
+namespace Benchmarks;
+
+public interface IShape
+{
+ double CalculateArea();
+}
+
+public class Shape : IShape
+{
+ public virtual double CalculateArea() => 0;
+}
+
+public class Circle : Shape
+{
+ public double Radius { get; init; }
+
+ public override double CalculateArea() => Math.PI * Radius * Radius;
+
+ public double CalculateAreaNonVirtual() => Math.PI * Radius * Radius;
+}
+
+public sealed class SealedCircle : Shape
+{
+ public double Radius { get; init; }
+
+ public override double CalculateArea() => Math.PI * Radius * Radius;
+}
+
+public class Rectangle : Shape
+{
+ public double Width { get; init; }
+
+ public double Height { get; init; }
+
+ public override double CalculateArea() => Width * Height;
+}
diff --git a/csharp-methods/VirtualMethodsInCSharp/Benchmarks/VirtualCallBenchmarks.cs b/csharp-methods/VirtualMethodsInCSharp/Benchmarks/VirtualCallBenchmarks.cs
new file mode 100644
index 0000000000..2bf5e784d5
--- /dev/null
+++ b/csharp-methods/VirtualMethodsInCSharp/Benchmarks/VirtualCallBenchmarks.cs
@@ -0,0 +1,82 @@
+using BenchmarkDotNet.Attributes;
+
+namespace Benchmarks;
+
+public class VirtualCallBenchmarks
+{
+ private const int Count = 1_000;
+
+ private Circle[] _circles = [];
+ private Shape[] _circlesAsShapes = [];
+ private Shape[] _mixedShapes = [];
+ private SealedCircle[] _sealedCircles = [];
+ private IShape[] _circlesAsInterfaces = [];
+ private Func[] _delegates = [];
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ _circles = Enumerable.Range(1, Count).Select(i => new Circle { Radius = i }).ToArray();
+ _circlesAsShapes = _circles;
+ _circlesAsInterfaces = _circles;
+ _sealedCircles = Enumerable.Range(1, Count).Select(i => new SealedCircle { Radius = i }).ToArray();
+ _mixedShapes = Enumerable.Range(1, Count)
+ .Select(i => i % 2 == 0 ? (Shape)new Circle { Radius = i } : new Rectangle { Width = i, Height = 2 })
+ .ToArray();
+ _delegates = _circles.Select(c => (Func)c.CalculateArea).ToArray();
+ }
+
+ [Benchmark(Baseline = true)]
+ public double NonVirtual()
+ {
+ var total = 0.0;
+ foreach (var circle in _circles)
+ total += circle.CalculateAreaNonVirtual();
+ return total;
+ }
+
+ [Benchmark]
+ public double VirtualOneType()
+ {
+ var total = 0.0;
+ foreach (var shape in _circlesAsShapes)
+ total += shape.CalculateArea();
+ return total;
+ }
+
+ [Benchmark]
+ public double VirtualTwoTypes()
+ {
+ var total = 0.0;
+ foreach (var shape in _mixedShapes)
+ total += shape.CalculateArea();
+ return total;
+ }
+
+ [Benchmark]
+ public double VirtualOnSealedType()
+ {
+ var total = 0.0;
+ foreach (var circle in _sealedCircles)
+ total += circle.CalculateArea();
+ return total;
+ }
+
+ [Benchmark]
+ public double Interface()
+ {
+ var total = 0.0;
+ foreach (var shape in _circlesAsInterfaces)
+ total += shape.CalculateArea();
+ return total;
+ }
+
+ [Benchmark]
+ public double Delegate()
+ {
+ var total = 0.0;
+ foreach (var calculateArea in _delegates)
+ total += calculateArea();
+ return total;
+ }
+}
diff --git a/csharp-methods/VirtualMethodsInCSharp/Tests/Tests.csproj b/csharp-methods/VirtualMethodsInCSharp/Tests/Tests.csproj
index 5bc695c747..b871eec308 100644
--- a/csharp-methods/VirtualMethodsInCSharp/Tests/Tests.csproj
+++ b/csharp-methods/VirtualMethodsInCSharp/Tests/Tests.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net10.0
enable
enable
@@ -10,11 +10,11 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/csharp-methods/VirtualMethodsInCSharp/Tests/VirtualMethodsInCSharpUnitTests.cs b/csharp-methods/VirtualMethodsInCSharp/Tests/VirtualMethodsInCSharpUnitTests.cs
index 6f59178904..6402a40744 100644
--- a/csharp-methods/VirtualMethodsInCSharp/Tests/VirtualMethodsInCSharpUnitTests.cs
+++ b/csharp-methods/VirtualMethodsInCSharp/Tests/VirtualMethodsInCSharpUnitTests.cs
@@ -96,5 +96,18 @@ public void WhenCircleClassGetShapeTypeMock_ThenCircleClassGetShapeTypeResult()
Assert.AreEqual("This is a circle", circleType);
}
+
+ [TestMethod]
+ public void WhenCircleClassDrawMock_ThenNotSupportedException()
+ {
+ var circleMock = new Mock();
+
+ var exception = Assert.ThrowsExactly(
+ () => circleMock.Setup(p => p.Draw()).Returns("Drawing a circle"));
+
+ StringAssert.Contains(exception.Message, "Unsupported expression: p => p.Draw()");
+ StringAssert.Contains(exception.Message,
+ "Non-overridable members (here: Circle.Draw) may not be used in setup / verification expressions.");
+ }
}
}
\ No newline at end of file
diff --git a/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp.sln b/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp.sln
index d69b38b9ba..4cfea7802d 100644
--- a/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp.sln
+++ b/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp.sln
@@ -7,20 +7,54 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VirtualMethodsInCSharp", "V
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{92452288-07FB-4BBD-8D38-12051459DBA3}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{A9E1E7FD-1F81-43D8-83AA-9F9305271A28}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{03E9D30B-AFB6-4528-925F-E9482515DC58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03E9D30B-AFB6-4528-925F-E9482515DC58}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {03E9D30B-AFB6-4528-925F-E9482515DC58}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {03E9D30B-AFB6-4528-925F-E9482515DC58}.Debug|x64.Build.0 = Debug|Any CPU
+ {03E9D30B-AFB6-4528-925F-E9482515DC58}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {03E9D30B-AFB6-4528-925F-E9482515DC58}.Debug|x86.Build.0 = Debug|Any CPU
{03E9D30B-AFB6-4528-925F-E9482515DC58}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03E9D30B-AFB6-4528-925F-E9482515DC58}.Release|Any CPU.Build.0 = Release|Any CPU
+ {03E9D30B-AFB6-4528-925F-E9482515DC58}.Release|x64.ActiveCfg = Release|Any CPU
+ {03E9D30B-AFB6-4528-925F-E9482515DC58}.Release|x64.Build.0 = Release|Any CPU
+ {03E9D30B-AFB6-4528-925F-E9482515DC58}.Release|x86.ActiveCfg = Release|Any CPU
+ {03E9D30B-AFB6-4528-925F-E9482515DC58}.Release|x86.Build.0 = Release|Any CPU
{92452288-07FB-4BBD-8D38-12051459DBA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{92452288-07FB-4BBD-8D38-12051459DBA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {92452288-07FB-4BBD-8D38-12051459DBA3}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {92452288-07FB-4BBD-8D38-12051459DBA3}.Debug|x64.Build.0 = Debug|Any CPU
+ {92452288-07FB-4BBD-8D38-12051459DBA3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {92452288-07FB-4BBD-8D38-12051459DBA3}.Debug|x86.Build.0 = Debug|Any CPU
{92452288-07FB-4BBD-8D38-12051459DBA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{92452288-07FB-4BBD-8D38-12051459DBA3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {92452288-07FB-4BBD-8D38-12051459DBA3}.Release|x64.ActiveCfg = Release|Any CPU
+ {92452288-07FB-4BBD-8D38-12051459DBA3}.Release|x64.Build.0 = Release|Any CPU
+ {92452288-07FB-4BBD-8D38-12051459DBA3}.Release|x86.ActiveCfg = Release|Any CPU
+ {92452288-07FB-4BBD-8D38-12051459DBA3}.Release|x86.Build.0 = Release|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Debug|x64.Build.0 = Debug|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Debug|x86.Build.0 = Debug|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Release|x64.ActiveCfg = Release|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Release|x64.Build.0 = Release|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Release|x86.ActiveCfg = Release|Any CPU
+ {A9E1E7FD-1F81-43D8-83AA-9F9305271A28}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp/Program.cs b/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp/Program.cs
index 2df4726a72..90c8e48077 100644
--- a/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp/Program.cs
+++ b/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp/Program.cs
@@ -5,7 +5,7 @@
var rectangle = new Rectangle() { Height = 2, Width = 3 };
Console.WriteLine($"Shape area: {shape.CalculateArea()}"); // Shape area: 0
-Console.WriteLine($"Circle area: {circle.CalculateArea()}"); // Circle area: 12,566370614359172
+Console.WriteLine($"Circle area: {circle.CalculateArea()}"); // Circle area: 12.566370614359172
Console.WriteLine($"Rectangle area: {rectangle.CalculateArea()}"); // Rectangle area: 6
Console.WriteLine($"Shape type: {shape.GetShapeType()}"); // Shape type: This is a generic shape
diff --git a/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp/VirtualMethodsInCSharp.csproj b/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp/VirtualMethodsInCSharp.csproj
index f02677bf64..dfb40caafc 100644
--- a/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp/VirtualMethodsInCSharp.csproj
+++ b/csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp/VirtualMethodsInCSharp.csproj
@@ -2,7 +2,7 @@
Exe
- net7.0
+ net10.0
enable
enable