如何在没有反射的情况下访问一系列类的公共属性

时间:2018-02-02 19:13:24

标签: c# .net inheritance design-patterns reflection

我正在开发一个遗留的C#应用​​程序,它包含许多业务实体类,这些类具有相同名称相同类型的5个公共属性(字符串和整数)。

我需要基于5个常见属性在实体类上实现一些业务流程逻辑。

class A
{
    public string CommonProperty1 {get;set;}
    public int CommonProperty2 {get;set;}
    public string CommonProperty3 {get;set;}
    public string CommonProperty4 {get;set;}
    public string CommonProperty5 {get;set;}

}
class B
{
    public string CommonProperty1 {get;set;}
    public int CommonProperty2 {get;set;}
    public string CommonProperty3 {get;set;}
    public string CommonProperty4 {get;set;}
    public string CommonProperty5 {get;set;}

}
class C
{
    public string CommonProperty1 {get;set;}
    public int CommonProperty2 {get;set;}
    public string CommonProperty3 {get;set;}
    public string CommonProperty4 {get;set;}
    public string CommonProperty5 {get;set;}

}
// there more of such business classes

public static BusinessHelpr
{
   public static DoSomethingOnClassAorBorC(object theRefrence)
   {
       theRefrence.CommonProperty4 = "result of some complex calculation";
       theRefrence.CommonProperty2 = 56; // result of some complex calculation;
       theRefrence.CommonProperty5 = "result of some complex calculation";
   }

}

如果这是一个绿地应用程序,我会继承一个包含5个属性的基类,并很好地实现所需的逻辑

但是,我们决定不进行任何重构或更改业务实体。他们无法触及。

因此,在我的帮助器类中,我需要找到一种方法来获取对象类型的引用,并通过字符串中的名称访问其属性。 这里一个明显的选择是反思。这意味着我得到一个类型,使用反射来按字符串中的名称访问其属性。 但是,我了解到在这种情况下使用反射意味着性能损失,这不是一个好习惯。

请注意,我简化了实际场景,专注于主要观点。所以创建一个方法不会起作用:

static DoSomethingOnClassAorBorC(string CommonProperty1, int CommonProperty2, string CommonProperty3,string CommonProperty4, string CommonProperty5)

除了反思,我的其他选择是什么?

2 个答案:

答案 0 :(得分:3)

选项1

我意识到你说你不想对模型做任何改动,但你没有涉及的一个选择是使用界面。

interface ICommon
{
    string CommonProperty1 {get;set;}
    int CommonProperty2 {get;set;}
    string CommonProperty3 {get;set;}
    string CommonProperty4 {get;set;}
    string CommonProperty5 {get;set;}
}

class A : ICommon
{
    public string CommonProperty1 {get;set;}
    public int CommonProperty2 {get;set;}
    public string CommonProperty3 {get;set;}
    public string CommonProperty4 {get;set;}
    public string CommonProperty5 {get;set;}
}
class B : ICommon
{
    public string CommonProperty1 {get;set;}
    public int CommonProperty2 {get;set;}
    public string CommonProperty3 {get;set;}
    public string CommonProperty4 {get;set;}
    public string CommonProperty5 {get;set;}
}
class C : ICommon
{
    public string CommonProperty1 {get;set;}
    public int CommonProperty2 {get;set;}
    public string CommonProperty3 {get;set;}
    public string CommonProperty4 {get;set;}
    public string CommonProperty5 {get;set;}
}

然后你可以使用:

static DoSomethingOnClassAorBorC(ICommon common)
{
    // implementation
}

你的任何实体都会#34;只是工作"。

您实际上不必对实体进行任何更改,除非向每个实体添加: Interface,这比使用继承更具侵略性。

选项2

如果您确实不想对您的模型进行任何更改,并且不希望产生巨大的性能损失(Reflection和dynamic都很昂贵),唯一的另一种选择是在每个模型上使用adapter pattern

interface ICommon
{
    string CommonProperty1 {get;set;}
    int CommonProperty2 {get;set;}
    string CommonProperty3 {get;set;}
    string CommonProperty4 {get;set;}
    string CommonProperty5 {get;set;}
}

为每个实体创建一个适配器类。

class AAdapter : ICommon
{
    private readonly A inner;

    public AAdapter(A inner)
    {
        if (inner == null)
            throw new ArgumentNullException(nameof(inner));
        this.inner = inner;
    }

    public string CommonProperty1 
    {
        get { return inner.CommonProperty1; }
        set { inner.CommonProperty1 = value; }
    }
    public int CommonProperty2
    {
        get { return inner.CommonProperty2; }
        set { inner.CommonProperty2 = value; }
    }
    public string CommonProperty3 
    {
        get { return inner.CommonProperty3; }
        set { inner.CommonProperty3 = value; }
    }
    public string CommonProperty4 
    {
        get { return inner.CommonProperty4; }
        set { inner.CommonProperty4 = value; }
    }
    public string CommonProperty5
    {
        get { return inner.CommonProperty5; }
        set { inner.CommonProperty5 = value; }
    }   
}

class BAdapter : ICommon
{
    private readonly B inner;

    public BAdapter(B inner)
    {
        if (inner == null)
            throw new ArgumentNullException(nameof(inner));
        this.inner = inner;
    }

    public string CommonProperty1 
    {
        get { return inner.CommonProperty1; }
        set { inner.CommonProperty1 = value; }
    }
    public int CommonProperty2
    {
        get { return inner.CommonProperty2; }
        set { inner.CommonProperty2 = value; }
    }
    public string CommonProperty3 
    {
        get { return inner.CommonProperty3; }
        set { inner.CommonProperty3 = value; }
    }
    public string CommonProperty4 
    {
        get { return inner.CommonProperty4; }
        set { inner.CommonProperty4 = value; }
    }
    public string CommonProperty5
    {
        get { return inner.CommonProperty5; }
        set { inner.CommonProperty5 = value; }
    }   
}

// Other similar adapters...

以与选项1相同的方式声明方法:

static DoSomethingOnClassAorBorC(ICommon common)
{
    // implementation
}

并包装您的实体类以使用它们。

DoSomethingOnClassAorBorC(new AAdapter(a));
DoSomethingOnClassAorBorC(new BAdapter(b));
DoSomethingOnClassAorBorC(new CAdapter(c));

答案 1 :(得分:2)

我能想到的最好的方法是简单地将A,B和C包装在另一个实现接口的类中,比如ICommon:

    public interface ICommon
    {
        string CommonProperty1 { get; set; }
        int CommonProperty2 { get; set; }
        string CommonProperty3 { get; set; }
        string CommonProperty4 { get; set; }
        string CommonProperty5 { get; set; }
    }

    public class A2 : ICommon
    {
        private readonly A _data;

        public A2(A data)
        {
            _data = data;
        }

        public string CommonProperty1
        {
            get { return _data.CommonProperty1; }
            set { _data.CommonProperty1 = value; }
        }
        public int CommonProperty2
        {
            get { return _data.CommonProperty2; }
            set { _data.CommonProperty2 = value; }
        }
        public string CommonProperty3
        {
            get { return _data.CommonProperty3; }
            set { _data.CommonProperty3 = value; }
        }
        public string CommonProperty4
        {
            get { return _data.CommonProperty4; }
            set { _data.CommonProperty4 = value; }
        }
        public string CommonProperty5
        {
            get { return _data.CommonProperty5; }
            set { _data.CommonProperty5 = value; }
        }
    }

    public class B2 : ICommon
    {
        private readonly B _data;

        public B2(B data)
        {
            _data = data;
        }

        public string CommonProperty1
        {
            get { return _data.CommonProperty1; }
            set { _data.CommonProperty1 = value; }
        }
        public int CommonProperty2
        {
            get { return _data.CommonProperty2; }
            set { _data.CommonProperty2 = value; }
        }
        public string CommonProperty3
        {
            get { return _data.CommonProperty3; }
            set { _data.CommonProperty3 = value; }
        }
        public string CommonProperty4
        {
            get { return _data.CommonProperty4; }
            set { _data.CommonProperty4 = value; }
        }
        public string CommonProperty5
        {
            get { return _data.CommonProperty5; }
            set { _data.CommonProperty5 = value; }
        }
    }

    public class C2 : ICommon
    {
        private readonly C _data;

        public C2(C data)
        {
            _data = data;
        }

        public string CommonProperty1
        {
            get { return _data.CommonProperty1; }
            set { _data.CommonProperty1 = value; }
        }
        public int CommonProperty2
        {
            get { return _data.CommonProperty2; }
            set { _data.CommonProperty2 = value; }
        }
        public string CommonProperty3
        {
            get { return _data.CommonProperty3; }
            set { _data.CommonProperty3 = value; }
        }
        public string CommonProperty4
        {
            get { return _data.CommonProperty4; }
            set { _data.CommonProperty4 = value; }
        }
        public string CommonProperty5
        {
            get { return _data.CommonProperty5; }
            set { _data.CommonProperty5 = value; }
        }
    }



        var list = new List<ICommon> { new A2(new A()), new A2(new A()), new B2(new B()), new C2(new C()) };
        foreach (var item in list)
        {
            item.CommonProperty1 = "a";
            item.CommonProperty2 = 2;
            item.CommonProperty3 = "b";
            item.CommonProperty4 = "c";
            item.CommonProperty5 = "d";
        }