Avoiding code duplication to access properties WITHOUT using reflection

I have this structure

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

As you can see, a lot of code is repeated in a class Helper(i.e. a method Bar) for different types A,B,C,IList<A>,IList<B>,IList<C>. Also, when a new list property is added to the classes, I need to go back and change the Helper class, which somehow contradicts the Open / Close principle.

I know how to use Reflectionto solve the problem, but I was looking for another smart and neat way to solve this problem, and not use Reflection.

I can add a new Interfacebut not base class

Any suggestion will be appreciated.

+4
source share
4 answers

, Foo() IFoo , Bar B, C D , Foo , Bar ( Foo())

looped ( Bar(IList<B/C/D> bs)):

void InvokeFoo(IEnumerable<IFoo> foos)
{
   foreach(var foo in foos)
   {
      foo.Foo();
   }
}

:

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

Edit

, (, B) , . (, A 2 , B 1, C D - ), , A, B, C .., "" . , ( ):

class Helper
{
    public void Bar(A a)
    {
        a.Foo();
        InvokeFoo(a.Bs, foo => InvokeFoo(((B)foo).Ds));
        InvokeFoo(a.Cs);
    }

    void InvokeFoo(IEnumerable<IFoo> foos, Action<IFoo> childAction = null)
    {
        foreach (var foo in foos)
        {
            foo.Foo();
            childAction?.Invoke(foo);
        }
    }
}

/

, ( ), SOLID ( ).

"" , , . ( ) Foo, :

class Helper
{
    private static readonly IDictionary<Type, Action<IFoo>> SpecialClassActions 
        = new Dictionary<Type, Action<IFoo>>
        {
            // Provide special handling for walking classes which have children
            {
                typeof(A),
                foo =>
                {
                    InvokeChildFoo(((A)foo).Bs);
                    InvokeChildFoo(((A)foo).Cs);
                }
            },
            {
                typeof(B),
                foo =>
                {
                    InvokeChildFoo(((B)foo).Ds);
                }
            }
            // Add more handling here as new subtypes are added
        };

    static void WalkFooHierarchy(IFoo foo)
    {
        foo.Foo();

        Action<IFoo> specialChildAction;
        if (SpecialClassActions.TryGetValue(foo.GetType(), out specialAction))
        {
            specialChildAction(foo);
        }
    }

    //  Replaces your Bar(IList<> ..) methods
    static void InvokeChildFoo(IEnumerable<IFoo> foos)
    {
        foreach (var foo in foos)
        {
            WalkFooHierarchy(foo);
        }
    }

, :

public void Bar(A a)
{
    Helper.WalkFooHierarchy(a);
}
+1

OPEN/CLOSE , - -

  • .
  • Helper. , . , , Foo Bar.

-

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

, , , /, , , Bar Helper .

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: , , , , - , . , , , ;)

+1

, :

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, , .

0
source

Source: https://habr.com/ru/post/1670700/


All Articles