Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions csharp-methods/VirtualMethodsInCSharp/Benchmarks/Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
</ItemGroup>

</Project>
4 changes: 4 additions & 0 deletions csharp-methods/VirtualMethodsInCSharp/Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using BenchmarkDotNet.Running;
using Benchmarks;

BenchmarkRunner.Run<VirtualCallBenchmarks>();
36 changes: 36 additions & 0 deletions csharp-methods/VirtualMethodsInCSharp/Benchmarks/Shapes.cs
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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<double>[] _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<double>)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;
}
}
12 changes: 6 additions & 6 deletions csharp-methods/VirtualMethodsInCSharp/Tests/Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

Expand All @@ -10,11 +10,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.11.0" />
<PackageReference Include="Moq" Version="4.21.0" />
<PackageReference Include="MSTest.TestAdapter" Version="4.5.1" />
<PackageReference Include="MSTest.TestFramework" Version="4.5.1" />
<PackageReference Include="coverlet.collector" Version="10.1.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,18 @@ public void WhenCircleClassGetShapeTypeMock_ThenCircleClassGetShapeTypeResult()

Assert.AreEqual("This is a circle", circleType);
}

[TestMethod]
public void WhenCircleClassDrawMock_ThenNotSupportedException()
{
var circleMock = new Mock<Circle>();

var exception = Assert.ThrowsExactly<NotSupportedException>(
() => 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.");
}
}
}
34 changes: 34 additions & 0 deletions csharp-methods/VirtualMethodsInCSharp/VirtualMethodsInCSharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
Loading