轻松实现深度Clone | Source Generators方式
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了轻松实现深度Clone | Source Generators方式相关的知识,希望对你有一定的参考价值。
前言
在开发中,我们经常需要创建某个类型实例的副本。
常用的方式,是继承ICloneable
接口,然后自行实现Clone()
,这会耗费一定的开发时间;或者使用序列化/反序列化方式变相实现,但是性能不高。
现在,可以尝试用Source Generators实现。
实现思路
首先,需要Clone的类必须声明一个特定的CloneableAttribute
,这样Source Generators才知道为谁实现Clone方法。
然后,Source Generators遍历该类型的所有属性,为其编写属性赋值代码。
如果属性本身也是Cloneable类型,那就调用属性对应类型的Clone方法,实现深度克隆。
具体代码
1.添加CloneableAttribute
向待编译项目加入CloneableAttribute代码:
const string cloneableAttributeText = @"using System;
namespace CloneableDemo
public sealed class CloneableAttribute : Attribute
public CloneableAttribute()
";
context.AddSource("CloneableAttribute", SourceText.From(cloneableAttributeText, Encoding.UTF8));
2.遍历CloneableAttribute声明类
找到声明了CloneableAttribute
的所有类型:
var cloneableAttribute = compilation.GetTypeByMetadataName("CloneableDemo.CloneableAttribute");
foreach (var classSymbol in classSymbols)
if (!classSymbol.TryGetAttribute(cloneableAttribute, out var attributes))
continue;
context.AddSource($"classSymbol.Name_clone.cs", SourceText.From(CreateCloneCode(classSymbol), Encoding.UTF8));
3.生成Clone代码
遍历属性,生成Clone方法:
private string CreateCloneableCode(INamedTypeSymbol classSymbol)
string namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
var propertyNames = classSymbol.GetMembers().OfType<IPropertySymbol>();
var codes = new StringBuilder();
foreach (var propertyName in propertyNames)
if (isCloneable(propertyName))
codes.AppendLine($@" propertyName = obj.propertyName?.Clone(),");
else
codes.AppendLine($@" propertyName = obj.propertyName,");
return $@"using System.Collections.Generic;
namespace namespaceName
public static class classSymbol.NameExtentions
public static classSymbol.Name Clone(this classSymbol.Name obj)
return new classSymbol.Name
codes.ToString()
;
";
4.使用
现在,就可以在目标项目中使用Clone方法了:
[Cloneable]
public class Class1
public string A get; set;
public Class2 B get; set;
[Cloneable]
public class Class2
public string A get; set;
var obj = new Class2()
A = "My IO",
;
var deep = new Class1()
A = "My IO",
B = obj
;
var clone = deep.Clone();
结论
有了Source Generators,可以让编译器帮我们自动实现Clone方法,既节约了开发时间,又保证了性能!
如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“
以上是关于轻松实现深度Clone | Source Generators方式的主要内容,如果未能解决你的问题,请参考以下文章