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

时间:2009-02-27 17:32:22

标签: c#

我遇到的情况是我正在映射具有继承层次结构的类。我有一个每个类都知道它需要的项目列表。例如:

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"};
}

我想进行一个方法调用,返回所有超类的聚合,如下所示:

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

我可以想到一些解决方案,但它们似乎过于复杂。我觉得有一个优雅的解决方案,我错过了。有人可以帮忙吗?

提前致谢!

5 个答案:

答案 0 :(得分:3)

您可以在名为GetAttributes的超类上拥有一个返回私有数组的虚方法/属性。然后,在每个子类中,像这样重写它。首先调用基类GetAttribute方法以获取基类数组,并将其与子类数组合并,然后返回新数组。

代码示例:

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();
        }
    }

答案 1 :(得分:1)

我很想开发一个自定义属性,该属性应用于我需要跟踪的每个属性,然后使用反射来枚举应用了该属性的属性。您可以使用延迟加载,以便仅填充一次属性列表。我也可能使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;
    }
}

答案 2 :(得分:0)

没有反射,就无法在当前状态下执行此操作。你可以做的是制作一个受保护的虚拟方法,它允许每个类将它们的属性添加到列表中并以这种方式聚合。

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);
  }
}

答案 3 :(得分:0)

我会采用更简单的方法:

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);
        }
    }
}

(P.S。这种层次结构很少用单继承语言来解决。)

答案 4 :(得分:0)

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");
    }
}