轻松实现深度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方式的主要内容,如果未能解决你的问题,请参考以下文章

探索gff/gtf格式

Lua自己实现深度克隆一个值

深度理解DOM拷贝clone()

Win#password;;processon #clone;;disassemble;;source find

实现list的深拷贝

转录组测序中 gene 和transcript 的区别