如何避免重复访问属性的代码而不使用反射

时间:2017-02-24 05:13:37

标签: c# .net oop

我有这些结构

class A : IFoo {
   Foo(){
      //do something
   }
   IList<B> Bs {get;set;}
   IList<C> Cs {get;set;}
}

class B : IFoo {
   Foo(){
      //do something
   }
   IList<D> Ds {get;set;}
}

class C : IFoo {
   Foo(){
      //do something
   }
}

class D : IFoo {
   Foo(){
      //do something
   }
}

class Helper{
  Bar(A a){
     a.Foo();
     Bar(a.Bs);
     Bar(a.Cs);
  }

  Bar(IList<B> bs)
  {
     foreach(var b in bs)
     {
        Bar(b);
     }
  }

  Bar(B b)
  {
     b.Foo();
     Bar(b.Ds);
  }

  Bar(IList<C> cs)
  {
     foreach(var c in cs)
     {
        Bar(c);
     }
  }

  Bar(C c)
  {
     c.Foo();
  }

  Bar(IList<D> ds)
  {
     foreach(var d in ds)
     {
        Bar(d);
     }
  }

  Bar(D d)
  {
     d.Foo();
  }
}
interface IFoo {
  void Foo();
}

如您所见,Helper类(即方法Bar)中针对不同类型的A,B,C,IList<A>,IList<B>,IList<C>重复了大量代码。此外,当一个新的列表属性被添加到类中时,我需要返回并更改Helper类,它与Open / Close主体相矛盾。

我知道如何使用Reflection来解决问题,但我正在寻找另一种聪明而巧妙的方法来解决这个问题,而不是使用反射。

我可以自由添加新的Interface但不能添加基类

任何建议都将受到赞赏

3 个答案:

答案 0 :(得分:1)

如果你想保持OPEN / CLOSE原则不变,你可以选择这样的东西 -

  • 每个课程都会根据需要延长。
  • 新课程不需要修改旧课程 - Helper。所以实现变得有点像下面的那个。无论您添加多少个类,每个类都负责自己的FooBar实现。

示例 -

public interface IFoo
{
    void Foo();
    void Bar();
}

public abstract class BaseFoo : IFoo
{
    public virtual void Foo()
    {
        //do nothing
    }

    public virtual void Bar()
    {
        //do nothing
    }
}

public class A : BaseFoo //replace with IFoo if you do not want the base class, in that case implement both methods
{
    IList<B> Bs { get; set; }
    IList<C> Cs { get; set; }

    public override void Bar()
    {
        base.Bar();

        foreach (var b in Bs)
        {
            b.Bar();
        }

        foreach (var c in Cs)
        {
            c.Bar();
        }
    }
}

public class B : BaseFoo //replace with IFoo if you do not want the base class, in that case implement both methods
{
    IList<D> Ds { get; set; }

    public override void Bar()
    {
        base.Bar();

        foreach (var d in Ds)
        {
            d.Bar();
        }
    }
}

public class C : BaseFoo //replace with IFoo if you do not want the base class, in that case implement both methods
{

}

public class D : BaseFoo //replace with IFoo if you do not want the base class, in that case implement both methods
{

}

public static class Helper
{
    public static void Bar(params IFoo[] foos)
    {
        foreach (var foo in foos)
        {
            foo.Bar();
        }
    }
}

答案 1 :(得分:1)

基于无价的建议和解决方案,我最终如下所示,此解决方案是打开/关闭的,并且只添加另一个列表,只应更改该类以及BarHelper中的所有重载已移除。

class Program
{
    static void Main(string[] args)
    {
        Helper.Bar(new A());
    }
}

public class A : IFoo, IMap
{
    public A()
    {
        Cs = new List<C> { new C(), new C() };
        Bs = new List<B> { new B(), new B() };
    }

    public void Foo()
    {
        Console.WriteLine("A");
    }
    public List<B> Bs { get; set; }
    public List<C> Cs { get; set; }

    public List<Func<dynamic, List<IFoo>>> Map()
    {
        return this.CreateMap()
            .Then(x => ((List<B>)x.Bs).ToList<IFoo>())
            .Then(x => ((List<C>)x.Cs).ToList<IFoo>());
    }

}

public class B : IFoo, IMap
{
    public B()
    {
        Ds = new List<D> { new D(), new D() };
    }
    public void Foo()
    {
        Console.WriteLine("B");
    }

    public List<Func<dynamic, List<IFoo>>> Map()
    {
        return this.CreateMap()
            .Then(x => ((List<D>)x.Ds).ToList<IFoo>());
    }

    public List<D> Ds { get; set; }
}

public class C : IFoo, IMap
{
    public void Foo()
    {
        Console.WriteLine("C");
    }

    public List<Func<dynamic, List<IFoo>>> Map()
    {
        return this.CreateMap();
    }
}

public class D : IFoo, IMap
{
    public void Foo()
    {
        Console.WriteLine("D");
    }

    public List<Func<dynamic, List<IFoo>>> Map()
    {
        return this.CreateMap();
    }
}

public static class Mapper
{
    public static List<Func<dynamic, List<IFoo>>> CreateMap(this IFoo item)
    {
        return new List<Func<dynamic, List<IFoo>>>();
    }

    public static List<Func<dynamic, List<IFoo>>> Then(this List<Func<dynamic, List<IFoo>>> list, Func<dynamic, List<IFoo>> expression)
    {
        list.Add(expression);
        return list;
    }
}
public class Helper
{
    public static void Bar(dynamic obj)
    {
        obj.Foo();
        var map = obj.Map();
        if (map != null)
        {
            foreach(var item in map)
            {
                var lists = item(obj);
                foreach(var list in lists)
                {
                    Bar(list);
                }
            }
        }
    } 

}

public interface IFoo
{
    void Foo();
}

public interface IMap 
{
    List<Func<dynamic, List<IFoo>>> Map();
}

@ brainlesscoder,@ StuartLC:既然你的解决方案也是正确的,我只会对它们进行投票,并且我没有将任何解决方案标记为保持此线程开放的答案,并且可能有人建议比我们更好的解决方案。如果您认为我的解决方案也很好,请投票;)

答案 2 :(得分:0)

在我看来,这是最直接的方式:

public static class Helper
{
    public static void Bar<F>(F f) where F : IFoo
    {
        f.Foo();
        Helper.Bar((f as A)?.Bs);
        Helper.Bar((f as A)?.Cs);
        Helper.Bar((f as B)?.Ds);
    }

    public static void Bar<F>(IList<F> fs) where F : IFoo
    {
        if (fs != null)
        {
            foreach (var f in fs)
            {
                Helper.Bar(f);
            }
        }
    }
}

现在,如果代码的其余部分定义如下:

public class A : IFoo
{
    public void Foo() { Console.Write("A"); }
    public IList<B> Bs { get; set; } = new List<B>() { new B(), new B(), };
    public IList<C> Cs { get; set; } = new List<C>() { new C(), new C(), };
}

public class B : IFoo
{
    public void Foo() { Console.Write("B"); }
    public IList<D> Ds { get; set; } = new List<D>() { new D(), new D(), };
}

public class C : IFoo
{
    public void Foo() { Console.Write("C"); }
}

public class D : IFoo
{
    public void Foo() { Console.Write("D"); }
}

public interface IFoo
{
    void Foo();
}

...然后你可以运行:

var a = new A();
var b = new B();
var c = new C();
var d = new D();

Helper.Bar(a);
Helper.Bar(b);
Helper.Bar(c);
Helper.Bar(d);

...你得到ABDDBDDCCBDDCD作为输出的预期结果。