Wydzielenie kodu do oddzielnej metody

0

Witam, Czy macie jakieś pomysły jak wydzielić powtarzający się kod do innej metody?
Mam około 10 prawie identycznych metod gdzie różni się tylko kilka rzeczy.

public void MyMethod(){
     foreach(var item in Items)
            {
                Product product = shop.Products.FirstOrDefault(e => e.Id == item.Id);
                if (product == null)
                {
                    allIds.Add(item.id.ToString());
                }
            }
}

W tych 10 metodach jedynymi różnicami jest typ kolekcji (tu List<Product> Items) i co za tym idzie typ obiektu w pętli.
Macie jakieś pomysły?

0

Tylko jest mały problem. Jak odwołam się w metodzie generycznej do właściwości "id", jeśli typy które będą "wkładane" do tej metody nie implementują interfejsu wspólnego, i na dodatek są z oddzielnej biblioteki. Wszystkie mają właściwość id.

1

genericsy po wyniesieniu tego kodu do wydzielonej klasy typu Adapter / Listener ?

0

Mógłbyś podać przykład jak taka klasa mogłaby wyglądać?

0

Kod nie sprawdzany, tylko idea


public class XxxxxxAdapter<T> {
    private List<T> items;
 public XxxxxxAdapter(List<T> list)
{
    items = list;
}  
public void MyMethod(){
     foreach(var item in Items)
            {
                Product product = shop.Products.FirstOrDefault(e => e.Id == item.Id);
                if (product == null)
                {
                    allIds.Add(item.id.ToString());
                }
            }
}
}

użycie jakoś tak (metakod):

  List<AlaMaKota> l;
  new XxxxxxAdapter( l).MyMethod();
lub sprawdź
    new XxxxxxAdapter<AlaMaKota>( l).MyMethod();

Nadal nie będzie Ci łatwo zgrać to z resztą, np sztywne shop.Products, ale może.

EDIT Oczywiście próbuj zmieniać typ Products na T, nikt Cię w tym nie zastąpi z braku pełnego kontekstu

EDIT2 Wyjadaczy proszę o ew, krytykę słowa Adapter, do wzorców mam stosunek pragmatyczny, nie religijny.

0

Tylko tu też występuje ten sam problem. W metodzie MyMethod nie możemy odwołać się do item.id :(

0

Możesz przekazywać IList do metody co pozwoli przekazać każdą listę albo object, a do pola id odwoływać się przez refleksje. Poniżej kod z mojego programu. Jestem początkujący, więc może to być zła, nieoptymalna metoda, ale u mnie działa ;)

		public virtual IList GetListOfObjects(object ndapiObjectList)
		{
			var convertedList = ((IEnumerable)ndapiObjectList).Cast<object>().ToList();

			var typeOfObjectInList = ndapiObjectList.GetType().GenericTypeArguments.FirstOrDefault();

			HashSet<Types> types = GetTypes();
			var xmlType = types.Where(x => x.NdapiType == typeOfObjectInList).SingleOrDefault().XmlType;

			var list = CreateGenericList(xmlType);

			foreach (var item in convertedList)
			{
				var createdInstance = Activator.CreateInstance(xmlType);
				XmlObject xmlObject = (XmlObject)createdInstance;

				this.SetPropertiesToSerialize((NdapiObject)item, xmlObject);

				//It's treated like normal trigger, so we can't create this. We only set property about formula calculation
				if (item.GetType().GetProperty("Name").GetValue(item)?.ToString() != "FORMULA-CALCULATION")
				{
					list.Add(xmlObject);
				}
			}

			return list;
		}

		private IList CreateGenericList(Type type)
		{
			var listType = typeof(List<>);
			var constructedListType = listType.MakeGenericType(type);
			var genericList = Activator.CreateInstance(constructedListType);

			return (IList)genericList;
		}
4

Jak już jechać refleksją, to można by użyć dynamic i wyjdzie mniej linijek. Ale ja bym przyjął lambdę która będzie wskazywać na id:

public void MyMethod<T>(List<T> items, Func<T, int> idSelector){
    foreach(var item in items)
    {
        var itemId = idSelector(item);
        Product product = shop.Products.FirstOrDefault(e => e.Id == itemId);
        if (product == null)
        {
            allIds.Add(itemId.ToString());
        }
    }
}

użycie

MyMethod(Items, x => x.Id)
2
        public void MyMethod<T>(IEnumerable<T> items, Func<T, int> getId)// Zakladam ze ID jest typu int, mozesz uzyc innego typu lub kolejny parameter generyczny
        {
            foreach (var item in items)
            {
                var itemId = getId(item);
                var product = shop.Products.FirstOrDefault(e => e.Id == itemId);
                if (product == null)
                {
                    allIds.Add(itemId.ToString());
                }
            }
        }

EDIT: Jakimś cudem nie zauważyłem postu @mad_penguin. Rozwiązanie które podał jest najrozsądniejsze. Po co wymyślać jakieś refleksje w tak banalnym przypadku?

0

A to nie chodzi przypadkiem o interfejs?

public interface IAnotherInterface : IProducts
    {
        void AnyMethod();
    }
    public interface IProducts
    {
        int id { get; }
    }

    public class MyProduct : IProducts
    {
        public int id { get; private set; } = 1;
    }
    public class MyObject : IAnotherInterface
    {
        public int id { get; private set; } = 1;

        public void AnyMethod()
        {
            throw new NotImplementedException();
        }
    }

Pobieranie ID:

public IEnumerable<int> ImportIds(IEnumerable<IProducts> objects)
        {
            return objects.Select(x => x.id);
        }

Przykład:

List<IProducts> products = new List<IProducts>();
            products.Add(new MyProduct());
            products.Add(new MyObject());
            var ids = ImportIds(products);
1

Strzelamy, strzelamy, marnujemy dużo amunicji, bo Kolega dawkuje nam informację kontekstową po kropelce.

1 użytkowników online, w tym zalogowanych: 0, gości: 1