简体   繁体   English

在C#中从子类聚合属性的优雅方法是什么?

[英]What is an elegant way to aggregate properties from subclasses in C#?

I have a situation where I am mapping classes that have an inheritance hierarchy. 我有一种情况,我正在映射具有继承层次结构的类。 I have a list of items that each class knows that it needs. 我有一个每个类都知道它需要的项目列表。 For example: 例如:

public class PersonMapper
{
    private string[] attributes = new[] {"firstName", "lastName"};
}

public class UserMapper : PersonMapper
{
    private string[] attributes = new[] {"username"};
}

public class EmployeeMapper : PersonMapper
{
    private string[] attributes = new[] {"employeeId"};
}

I would like to make a method call that returns the aggregate of all of the super classes like this: 我想进行一个方法调用,返回所有超类的聚合,如下所示:

EmployeeMapper mapper = new EmployeeMapper();
string[] attributes = mapper.GetAttributes();
Assert.That(attributes, Has.Member("firstname"));

I can think of some solutions, but they seem overly complicated. 我可以想到一些解决方案,但它们似乎过于复杂。 I feel like there is an elegant solution to this that I am missing. 我觉得有一个优雅的解决方案,我错过了。 Can anyone help? 有人可以帮忙吗?

Thanks in advance! 提前致谢!

You can have a virtual method/property on the superclass called GetAttributes that returns the private array. 您可以在名为GetAttributes的超类上拥有一个返回私有数组的虚方法/属性。 Then, in each subclass, override it like so. 然后,在每个子类中,像这样重写它。 First call the base GetAttribute method to get the base classes array, and the combine that with the subclasses array, and return the new array. 首先调用基本GetAttribute方法以获取基类数组,以及与子类数组的组合,并返回新数组。

Code sample: 代码示例:

public class PersonMapper
    {
        private string[] attributes = new[] { "firstName", "lastName" };
        public virtual string[] GetAttributes()
        {
            return attributes;
        }
    }

 public class EmployeeMapper : PersonMapper
    {
        private string[] attributes = new[] { "employeeId" };
        public override string[] GetAttributes()
        {
            return base.GetAttributes().Union(this.attributes).ToArray();
        }
    }

I'd be tempted to develop a custom attribute that gets applied to each of the properties that I care to track and then use reflection to enumerate the properties with that attribute applied. 我很想开发一个自定义属性,该属性应用于我要跟踪的每个属性,然后使用反射来枚举应用了该属性的属性。 You could use lazy loading so that the attribute list only gets populated once. 您可以使用延迟加载,以便仅填充一次属性列表。 I'd also probably make GetAttributes() a static (class) method. 我也可能使GetAttributes()成为一个静态(类)方法。

public class MappedAttribute : Attribute
{
}

public class Person
{
    [Mapped]
    public string FirstName { get; set; }

    [Mapped]
    public string LastName { get; set; }

    public string DisplayName
    {
        get { return FirstName + " " + LastName; }
    }
}

public static class Mapper
{
    public static IList<string> Attributes( Type t )
    {
          List<string> attributes = new List<string>();

          foreach (PropertyInfo pInfo in t.GetProperties())
          {
              MappedAttribute attr = pInfo.GetCustomAttributes(typeof(MappedAttribute),false)
                                          .Cast<MappedAttribute>()
                                          .FirstOrDefault();
              if (attr != null)
              {
                  attributes.Add(pInfo.Name);
              }
          }

          return attributes;
    }
}

Without reflection, there is no way to do it in the current state. 如果没有反射,就无法在当前状态下执行此操作。 What you could do though is make a protected virtual method which allows each class to add their attributes to a list and aggregate that way. 你可以做的是制作一个受保护的虚拟方法,它允许每个类将它们的属性添加到列表中并以这种方式聚合。

public class PersonMapper {
  protected virtual void AggregateAttributes(List<string> list) {
    list.AddRange(attributes);
  }
  public List<string> GetAttributes() {
    List<string> list = new List<string>();
    AggregateAttributes(list);
    return list;
  }
}

public class UserMapper {
  protected override void AggergateAttributes(List<string> list) {
    base.AggregateAttributes(list);
    list.AddRange(attributes);
  }
}

public class EmployeeMapper {
  protected override void AggergateAttributes(List<string> list) {
    base.AggregateAttributes(list);
    list.AddRange(attributes);
  }
}

I would go for a simpler approach: 我会采取更简单的方法:

class Entity {
    public virtual IEnumerable<string> Attributes { get { yield return "Name"; } }
}

class Person : Entity {
    public override IEnumerable<string> Attributes {
        get {
            return new string[] { "FirstName", "LastName" }
                .Concat(base.Attributes);
        }
    }
}

class User : Person {
    public override IEnumerable<string> Attributes {
        get {
            return new string[] { "UserName" }
                .Concat(base.Attributes);
        }
    }
}

(PS These kinds of hierarchies rarely work out in single-inheritance languages.) (PS这些层次结构在单继承语言中很少有用。)

public class PersonMapper
{
    protected List<string> attributes =
        new List<string>() {"firstName", "lastName"};
    public string[] GetAttributes()
    {
        //defensive copy
        return attributes.ToArray();
    }
}

public class EmployeeMapper : PersonMapper
{
    public EmployeeMapper()
    {
        attributes.Add("employeeId");
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 什么是尝试在 C# 中捕获属性的优雅方法 - What is an elegant way to try catch properties in C# 基于 C# 中另一个列表中的 Id 映射一个列表中某些属性的优雅方法 - Elegant way to map some properties in one List based on Id from another List in C# C#分配属性值而不是复制的优雅方法 - C# elegant way to assign properties values rather then duplication 从C#中的另一个列表更新一个列表中的项目的最优雅方法是什么? - what is the most elegant way to update an item in one list from another list in C#? 用C#在不同堆栈上驱动相同API的一种优雅方法是什么 - What is an elegant way to drive same APIs on different stacks in C# 在C#中进行冒泡排序的最优雅方法是什么? - What's the most elegant way to bubble-sort in C#? 是表达的属性 <TDelegate> C#中固有的子类? - Are properties of Expression<TDelegate> subclasses intrinsic in C#? C#优雅方式检查所有浅属性是否为null(或任何属性不为null) - C# elegant way to check if all shallow properties are null (or any property is not null) 如果只有某些对象属性为空,如何以更优雅的方式检查 C#? - How to check with C#, in more elegant way, if only some of the object properties are null? 将属性从对象复制到另一个的优雅方法 - Elegant way to copy properties from object to another
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM