如何避免C#接口实现重复代码?类结构优化方案咨询
C#中复用接口实现代码的可行方案
现有大量密封类,各自继承不同抽象类,同时实现InterfaceWithProperties接口,当前每个类都重复编写接口成员的实现代码,违反DRY原则。需要找到类似“增强类型”的方式复用接口实现,避免重复代码。
以下是三种可行方案:
方案1:默认接口方法(C# 8.0+)
直接在接口中提供带私有成员存储的默认实现,实现类无需重复编写接口属性代码,直接复用接口逻辑。C# 10及以上支持接口私有字段,完美适配需求:
public interface InterfaceWithProperties { // 接口私有字段存储属性值(C# 10+支持) private int _integerProperty; private string _stringProperty; [SomeAttribute] public int IntegerProperty { get => _integerProperty; set => _integerProperty = value; } [SomeAttribute] public string StringProperty { get => _stringProperty; set => _stringProperty = value; } } public abstract class AbstractClass1 { public abstract Guid GuidProperty1 { get; set; } } public sealed class DerivativeClass1 : AbstractClass1, InterfaceWithProperties { [TargetAttribute(ValueForDerivativeClass1)] public override Guid GuidProperty1 { get; set; } // 无需重复编写接口属性,直接使用接口默认实现 }
这种方式最接近你期望的“augmentation”效果,代码简洁且无冗余。
方案2:组合模式(适配类)
创建封装接口实现的适配类,通过组合方式在密封类中复用逻辑,兼容性覆盖所有C#版本:
// 封装接口实现的适配类,仅需编写一次 public class PropertiesImplementation : InterfaceWithProperties { [SomeAttribute] public int IntegerProperty { get; set; } [SomeAttribute] public string StringProperty { get; set; } } public sealed class DerivativeClass1 : AbstractClass1, InterfaceWithProperties { private readonly PropertiesImplementation _props = new(); [TargetAttribute(ValueForDerivativeClass1)] public override Guid GuidProperty1 { get; set; } // 显式接口实现,转发调用给适配类 [SomeAttribute] int InterfaceWithProperties.IntegerProperty { get => _props.IntegerProperty; set => _props.IntegerProperty = value; } [SomeAttribute] string InterfaceWithProperties.StringProperty { get => _props.StringProperty; set => _props.StringProperty = value; } }
此方式代码量略多于默认接口方法,但兼容性更强,适合低版本C#项目。
方案3:源代码生成器(C# 9.0+)
通过编写源代码生成器,编译时自动为符合条件的密封类生成接口成员实现,完全消除重复代码:
生成器核心代码(简化版)
[Generator] public class PropertiesGenerator : ISourceGenerator { public void Execute(GeneratorExecutionContext context) { var interfaceSymbol = context.Compilation.GetTypeByMetadataName("YourNamespace.InterfaceWithProperties"); if (interfaceSymbol == null) return; // 扫描所有实现接口的密封类 foreach (var typeSymbol in context.Compilation.SyntaxTrees .SelectMany(tree => tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>()) .Select(syntax => context.Compilation.GetSemanticModel(syntax.SyntaxTree).GetDeclaredSymbol(syntax)) .OfType<INamedTypeSymbol>() .Where(t => t.IsSealed && t.AllInterfaces.Contains(interfaceSymbol))) { // 自动生成属性实现代码 var source = $$""" namespace {{typeSymbol.ContainingNamespace}} { public partial class {{typeSymbol.Name}} { [SomeAttribute] public int IntegerProperty { get; set; } [SomeAttribute] public string StringProperty { get; set; } } } """; context.AddSource($"{typeSymbol.Name}_Properties.g.cs", source); } } public void Initialize(GeneratorInitializationContext context) { } }
密封类代码(仅需定义为partial)
public sealed partial class DerivativeClass1 : AbstractClass1, InterfaceWithProperties { [TargetAttribute(ValueForDerivativeClass1)] public override Guid GuidProperty1 { get; set; } }
这种方式适合大量类的场景,编译时自动生成代码,无运行时开销。
内容的提问来源于stack exchange,提问作者SangYoung Ha
相关产品推荐
相关产品推荐

