Suggestions for working with this inherited common method

We inherited a project that is a wrapper around a section of the core business model.

There is one method that takes a generic type, finds elements matching that type from a member, and then returns a list of that type.

public List<T> GetFoos<T>() { List<IFoo> matches = Foos.FindAll( f => f.GetType() == typeof(T) ); List<T> resultList = new List<T>(); foreach (var match in matches) { resultList.Add((T)obj); } } 

Foos can hold the same object in different classes in the inheritance hierarchy to summarize the results differently for different user interface presentations. There are 20+ different types of descendants that GetFoos can return.

Existing code basically has a large switch statement copied and pasted into the whole code. The code in each section calls GetFoos with the appropriate type.

We are currently reorganizing this into one consolidated area, but as we do this, we are considering other ways of working with this method.

One thought was to use reflection to pass in a type, and this worked fine until we realized that Invoke returned the object and that it needed to be somehow passed to List <T>.

Another was to simply use the switch statement before 4.0, and then use the parameters of the dynamic language.

We welcome any alternative thoughts on how we can work with this method. I left the code pretty concise, but if you want to know any additional data, just ask.

Update

The switch statement originally used strings, and the first pass moved it to Presenter with something like this: (Refactoring was not performed on the switch where the data was).

 // called on an event handler in FooPresenter // view is the interface for the ASPX page injected into FooPresenter constructor // wrapper is the instance of the model wrapper that has the GetFoos method // selectedFooName is the value of a DropDownList in the Page // letting the user say how they want to see the animals // its either one big group (Animal) // or individual types (Tiger, Lion) private void LoadFoos(string selectedFooName) { switch (selectedFooName) { case "Animal": // abstract base class for all other types this.view.SetData(this.wrapper.GetFoos<Animal>(); case "Lion": this.view.SetData(this.wrapper.GetFoos<Lion>(); break; case "Tiger": this.view.SetData(this.wrapper.GetFoos<Tiger>(); break; case "Bear": this.view.SetData(this.wrapper.GetFoos<Bear>(); break; } } 

View implementation (codebehind for ASPX page)

 public void SetData<T>(List<T> data) { // there is a multiview on the page that contains user controls with // grid layouts for the different types // there is a control for the common type of "Animal" // and other controls for Tiger, Bear, etc // the controls contain a 3rd party grid of pain // and the grids' binding event handlers cast the data item // for the row and do some stuff with it specific to that type } 

Our first pass was to at least use Type in a switch statement or add an enumeration.

I played using the strategy template, but I had to stop when I got to the factory loading, returning the list again, and realized that I did not have it.

+4
source share
2 answers

This is difficult without seeing the code calling GetFoos () ... If you can show more code describing what it's called, we can suggest how to reorganize it.

It seems like the solution is to make your routine routine routine, so that it can avoid "switching" around 20 types, simply using one common type, specified if necessary. However, this may not be possible, but again, without code, it's hard to understand ...

By saying, you can reorganize GetFoos much easier:

 public List<T> GetFoos<T>() { return Foos.OfType<T>().ToList(); } 

Edit: As Eric Lippert points out, the above code returns any type that is type T, but also subclasses of T. Although this is most likely a behavior that would really be desirable, it is different from the source code, If by any because it’s undesirable, you can use:

 public List<T> GetFoos<T>() { Type type = typeof(T); return Foos.Where(item => item.GetType() == type).ToList(); } 

This will have the same behavior as the source code.

+2
source

Something like that?

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace SO_2480770 { interface IFoo {} class MyBase : IFoo {} class Bar : MyBase {} class Program { IEnumerable<IFoo> Foos { get; set; } static void Main(string[] args) { List<MyBase> bases = new List<MyBase>() { new MyBase(), new MyBase() }; List<Bar> bars = new List<Bar>() { new Bar(), new Bar() }; Program p = new Program(); p.Foos = bases.Concat(bars); var barsFromFoos = p.GetFoos<Bar>(); var basesFromFoos = p.GetFoos<MyBase>(); Debug.Assert(barsFromFoos.SequenceEqual(bars)); Debug.Assert(basesFromFoos.SequenceEqual(bases.Concat(bars))); Debug.Assert(!barsFromFoos.SequenceEqual(bases)); Console.ReadLine(); } public List<T> GetFoos<T>() where T : IFoo { return Foos.OfType<T>().ToList(); } } } 

To get rid of large switch statements, you either need to push generics. I.E. make a method in which the switch statement accepts a parameter of a general type, and continue moving until you can go further, if you need, up the calling chain. When it gets too complicated, think about design patterns such as abstract factory, factory, pattern methods, etc ... It depends on how complex the calling code is.

0
source

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


All Articles