Skip to content

Commit cf08a5a

Browse files
committed
add support for system.drawing.font
1 parent 19241db commit cf08a5a

File tree

11 files changed

+124
-9
lines changed

11 files changed

+124
-9
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Drawing;
2+
using FastCloner.Code;
3+
4+
namespace FastCloner.Contrib;
5+
6+
public static class ContribTypeHandlers
7+
{
8+
private static bool registered;
9+
10+
public static void Register()
11+
{
12+
if (registered)
13+
{
14+
return;
15+
}
16+
17+
registered = true;
18+
19+
FastClonerExprGenerator.CustomTypeHandlers.TryAdd(
20+
typeof(Font),
21+
ProcessFont
22+
);
23+
}
24+
25+
private static object ProcessFont(Type type, bool unboxStruct, FastClonerExprGenerator.ExpressionPosition position)
26+
{
27+
return (Func<object, FastCloneState, object>)((obj, state) =>
28+
{
29+
Font font = (Font)obj;
30+
Font result = (Font)font.Clone();
31+
state.AddKnownRef(obj, result);
32+
return result;
33+
});
34+
}
35+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<ImplicitUsings>enable</ImplicitUsings>
5+
<Nullable>enable</Nullable>
6+
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
7+
<LangVersion>preview</LangVersion>
8+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
9+
<Title>Special types support for FastCloner</Title>
10+
<Description>Extends FastCloner with support for certain special types.</Description>
11+
<Copyright>Matěj Štágl</Copyright>
12+
<PackageProjectUrl>git</PackageProjectUrl>
13+
<PackageIcon>icon.jpg</PackageIcon>
14+
<RepositoryUrl>https://github.com/lofcz/FastCloner</RepositoryUrl>
15+
<RepositoryType>git</RepositoryType>
16+
<PackageTags>fastcloner,clone,deepclone,replicate,duplicate</PackageTags>
17+
</PropertyGroup>
18+
19+
<ItemGroup>
20+
<ProjectReference Include="..\FastCloner\FastCloner.csproj" />
21+
</ItemGroup>
22+
23+
<ItemGroup>
24+
<PackageReference Include="System.Drawing.Common" Version="[8.0.3,)" />
25+
</ItemGroup>
26+
27+
<ItemGroup>
28+
<None Update="icon.jpg">
29+
<Pack>true</Pack>
30+
<PackagePath></PackagePath>
31+
</None>
32+
</ItemGroup>
33+
34+
</Project>

FastCloner.Contrib/icon.jpg

4.84 KB
Loading

FastCloner.Tests/FastCloner.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
</ItemGroup>
5353

5454
<ItemGroup>
55+
<ProjectReference Include="..\FastCloner.Contrib\FastCloner.Contrib.csproj" />
5556
<ProjectReference Include="..\FastCloner\FastCloner.csproj" />
5657
</ItemGroup>
5758

FastCloner.Tests/SpecificScenariosTest.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,20 @@
1010
using System.Net;
1111
using System.Net.Http.Headers;
1212
using System.Text;
13+
using FastCloner.Contrib;
1314
using Microsoft.EntityFrameworkCore;
1415

1516
namespace FastCloner.Tests;
1617

1718
[TestFixture]
1819
public class SpecificScenariosTest
1920
{
21+
[OneTimeSetUp]
22+
public void Setup()
23+
{
24+
ContribTypeHandlers.Register();
25+
}
26+
2027
[Test]
2128
public void Test_ExpressionTree_OrderBy1()
2229
{
@@ -456,6 +463,30 @@ public void HttpResponse_Clone()
456463
});
457464
}
458465

466+
[Test]
467+
[Platform("win")]
468+
public void Font_Clone()
469+
{
470+
// Arrange
471+
Font original = new Font("Arial", 12, FontStyle.Bold | FontStyle.Italic);
472+
473+
// Act
474+
Font? cloned = FastCloner.DeepClone(original);
475+
476+
// Assert
477+
Assert.Multiple(() =>
478+
{
479+
Assert.That(cloned, Is.Not.SameAs(original), "Should be different instance");
480+
Assert.That(cloned.Name, Is.EqualTo("Arial"), "Font name should be copied");
481+
Assert.That(cloned.Size, Is.EqualTo(12), "Font size should be copied");
482+
Assert.That(cloned.Style, Is.EqualTo(FontStyle.Bold | FontStyle.Italic), "Font style should be copied");
483+
Assert.That(cloned.Unit, Is.EqualTo(original.Unit), "Font unit should be copied");
484+
Assert.That(cloned.GdiCharSet, Is.EqualTo(original.GdiCharSet), "GDI charset should be copied");
485+
Assert.That(cloned.GdiVerticalFont, Is.EqualTo(original.GdiVerticalFont), "GDI vertical font should be copied");
486+
});
487+
}
488+
489+
459490
[Test]
460491
public void HttpRequest_With_StreamContent_Clone()
461492
{

FastCloner.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastCloner", "FastCloner\Fa
1212
EndProject
1313
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastCloner.Tests", "FastCloner.Tests\FastCloner.Tests.csproj", "{873A4571-F5B5-4C35-B8A9-335664473194}"
1414
EndProject
15+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastCloner.Contrib", "FastCloner.Contrib\FastCloner.Contrib.csproj", "{3CB1B8F0-332F-4B5F-90A4-D8523956B22F}"
16+
EndProject
1517
Global
1618
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1719
Debug|Any CPU = Debug|Any CPU
@@ -26,6 +28,10 @@ Global
2628
{873A4571-F5B5-4C35-B8A9-335664473194}.Debug|Any CPU.Build.0 = Debug|Any CPU
2729
{873A4571-F5B5-4C35-B8A9-335664473194}.Release|Any CPU.ActiveCfg = Release|Any CPU
2830
{873A4571-F5B5-4C35-B8A9-335664473194}.Release|Any CPU.Build.0 = Release|Any CPU
31+
{3CB1B8F0-332F-4B5F-90A4-D8523956B22F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32+
{3CB1B8F0-332F-4B5F-90A4-D8523956B22F}.Debug|Any CPU.Build.0 = Debug|Any CPU
33+
{3CB1B8F0-332F-4B5F-90A4-D8523956B22F}.Release|Any CPU.ActiveCfg = Release|Any CPU
34+
{3CB1B8F0-332F-4B5F-90A4-D8523956B22F}.Release|Any CPU.Build.0 = Release|Any CPU
2935
EndGlobalSection
3036
GlobalSection(SolutionProperties) = preSolution
3137
HideSolutionNode = FALSE

FastCloner/AssemblyInfo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Runtime.CompilerServices;
22

33
[assembly: InternalsVisibleTo("FastCloner.Tests")]
4+
[assembly: InternalsVisibleTo("FastCloner.Contrib")]
45
namespace FastCloner;

FastCloner/Code/BadTypes.cs

Lines changed: 0 additions & 6 deletions
This file was deleted.

FastCloner/Code/FastClonerExprGenerator.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace FastCloner.Code;
99

1010
internal static class FastClonerExprGenerator
1111
{
12+
internal static readonly ConcurrentDictionary<Type, Func<Type, bool, ExpressionPosition, object>> CustomTypeHandlers = [];
13+
1214
private static readonly ConcurrentDictionary<FieldInfo, bool> _readonlyFields = new ConcurrentDictionary<FieldInfo, bool>();
1315

1416
private static readonly MethodInfo _fieldSetMethod;
@@ -39,7 +41,7 @@ internal static void ForceSetField(FieldInfo field, object obj, object value)
3941
}
4042
}
4143

42-
private readonly record struct ExpressionPosition(int Depth, int Index)
44+
internal readonly record struct ExpressionPosition(int Depth, int Index)
4345
{
4446
public ExpressionPosition Next() => this with { Index = Index + 1 };
4547
public ExpressionPosition Nested() => new ExpressionPosition(Depth + 1, 0);
@@ -62,7 +64,7 @@ private static LabelTarget CreateLoopLabel(ExpressionPosition position)
6264
{
6365
[typeof(ExpandoObject)] = (_, _, position) => GenerateExpandoObjectProcessor(position),
6466
[typeof(HttpRequestOptions)] = (_, _, position) => GenerateHttpRequestOptionsProcessor(position),
65-
[typeof(Array)] = (type, _, _) => GenerateProcessArrayMethod(type)
67+
[typeof(Array)] = (type, _, _) => GenerateProcessArrayMethod(type),
6668
}.ToFrozenDictionary();
6769

6870
private static object GenerateProcessMethod(Type type, bool unboxStruct, ExpressionPosition position)
@@ -71,6 +73,11 @@ private static object GenerateProcessMethod(Type type, bool unboxStruct, Express
7173
{
7274
return handler.Invoke(type, unboxStruct, position);
7375
}
76+
77+
if (CustomTypeHandlers.TryGetValue(type, out Func<Type, bool, ExpressionPosition, object>? contribHandler))
78+
{
79+
return contribHandler.Invoke(type, unboxStruct, position);
80+
}
7481

7582
if (IsDictionaryType(type))
7683
{

FastCloner/Code/PartialModels.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace FastCloner.Code;
2+
3+
internal interface IFastClonerTypeRegistry
4+
{
5+
void RegisterTypeHandler(Type type, object handler);
6+
}

0 commit comments

Comments
 (0)