Budowa Struktury odwołań

0

Witam buduje serwis do pewnej aplikacji która będzie dość obszerna rozwiązanie takie jak te poniżej mnie nie interesuje

Nie mylić tego przykładu górnego Servisu iż działa tak jak jest zaimplementowany poniżej

public class JakisService
{
void GetFooById(int id)
void GetFooByValue(int value)
void GetFooByName(string name )
...
}

Mało mnie interesuje bo w tym momencie interface będzie implementował ponad 50 rożnych odwołań a chce je zmniejszyć do 4 ;) wprowadzając kryteria pobierania. Bardzo fajnie to działa w Selenium tylko nie wiem jak osiągnąć taki efekt

........
var element = new JakisService();

var sample1 = element.GetFoo(By.Id("cos"));  
var sample2 = element.GetFoo(By.Value("cos"));
var sample3 = element.GetFoo(By.Name("cos"));
...

Takie wywołanie by mnie interesowało, jest czytelne przyjemne i szybkie do implementacji. Tak jak pisałem coś podobnego wykorzystuje Selenium do Idrivera is prawdza się rewelacyjnie.

Nie wiem jak zrobić te By. bo albo to enum albo interface i nie wiem jak to powiązać z sobą; Za rady bym dziękował.

0

Jak to wygląda w selenium

var IDriver = new IWebDriver(); // jakoś tak bo definiujemy tutaj przeglądarkę

odwołanie do pobierania elementu wygląda coś podobnego chciał bym stworzyć

IWebElement element = IDriver.FindElement(By.Id(serchValue)); // zwraca element
List<IWebElement> elements = IDriver.FindElements(By.Id(serchValue)); 

Tak wygląda interface FindElement

public interface ISearchContext
    {
        IWebElement FindElement(By by);
        ReadOnlyCollection<IWebElement> FindElements(By by);
    }

A tak wygląda konstrukcja By który jest bardziej rozbudowany niż myślałem ;) Nie wiem co oznacza [Serializable] ;) oraz dla czego jest to tak zbudowane do większości niestety nie mam podglądu

[Serializable]
    public class By
    {
        protected By();
        protected By(Func<ISearchContext, IWebElement> findElementMethod, Func<ISearchContext, ReadOnlyCollection<IWebElement>> findElementsMethod);

        public static bool operator !=(By one, By two);
        public static bool operator ==(By one, By two);

        protected string Description { get; set; }
        protected Func<ISearchContext, IWebElement> FindElementMethod { get; set; }
        protected Func<ISearchContext, ReadOnlyCollection<IWebElement>> FindElementsMethod { get; set; }

        public static By ClassName(string classNameToFind);
        public static By CssSelector(string cssSelectorToFind);
        public override bool Equals(object obj);
        public virtual IWebElement FindElement(ISearchContext context);
        public virtual ReadOnlyCollection<IWebElement> FindElements(ISearchContext context);
        public override int GetHashCode();
        public static By Id(string idToFind);
        public static By LinkText(string linkTextToFind);
        public static By Name(string nameToFind);
        public static By PartialLinkText(string partialLinkTextToFind);
        public static By TagName(string tagNameToFind);
        public override string ToString();
        public static By XPath(string xpathToFind);
    }

Tak mniej więcej wygląda to co jest zwracane

 


Defakto ja tego nie potrzebuje bo tak naprawdę nie działam na żywym elemencie tylko przechowuje w nim dane nic więcej.

 public interface IWebElement : ISearchContext
    {
        bool Displayed { get; }
        bool Enabled { get; }
        System.Drawing.Point Location { get; }
        bool Selected { get; }
        System.Drawing.Size Size { get; }
        string TagName { get; }
        string Text { get; }

        void Clear();
        void Click();
        string GetAttribute(string attributeName);
        string GetCssValue(string propertyName);
        void SendKeys(string text);
        void Submit();
    }

Natomiast tak wygląda Budowa samego Drivera

 
 public class RemoteWebDriver : IWebDriver, IDisposable, ISearchContext, IJavaScriptExecutor, IFindsById, IFindsByClassName, IFindsByLinkText, IFindsByName, IFindsByTagName, IFindsByXPath, IFindsByPartialLinkText, IFindsByCssSelector, ITakesScreenshot, IHasInputDevices, IHasCapabilities, IHasWebStorage, IHasLocationContext, IHasApplicationCache, IAllowsFileDetection, IHasSessionId
    {
        protected static readonly TimeSpan DefaultCommandTimeout;

        public RemoteWebDriver(ICapabilities desiredCapabilities);
        public RemoteWebDriver(ICommandExecutor commandExecutor, ICapabilities desiredCapabilities);
        public RemoteWebDriver(Uri remoteAddress, ICapabilities desiredCapabilities);
        public RemoteWebDriver(Uri remoteAddress, ICapabilities desiredCapabilities, TimeSpan commandTimeout);

        public IApplicationCache ApplicationCache { get; }
        public ICapabilities Capabilities { get; }
        protected ICommandExecutor CommandExecutor { get; }
        public string CurrentWindowHandle { get; }
        public virtual IFileDetector FileDetector { get; set; }
        public bool HasApplicationCache { get; }
        public bool HasLocationContext { get; }
        public bool HasWebStorage { get; }
        public IKeyboard Keyboard { get; }
        public ILocationContext LocationContext { get; }
        public IMouse Mouse { get; }
        public string PageSource { get; }
        public SessionId SessionId { get; }
        public string Title { get; }
        public string Url { get; set; }
        public IWebStorage WebStorage { get; }
        public ReadOnlyCollection<string> WindowHandles { get; }

        public void Close();
        protected virtual RemoteWebElement CreateElement(string elementId);
        public void Dispose();
        protected virtual void Dispose(bool disposing);
        protected virtual Response Execute(string driverCommandToExecute, Dictionary<string, object> parameters);
        public object ExecuteAsyncScript(string script, params object[] args);
        public object ExecuteScript(string script, params object[] args);
        protected object ExecuteScriptCommand(string script, string commandName, params object[] args);
        public IWebElement FindElement(By by);
        protected IWebElement FindElement(string mechanism, string value);
        public IWebElement FindElementByClassName(string className);
        public IWebElement FindElementByCssSelector(string cssSelector);
        public IWebElement FindElementById(string id);
        public IWebElement FindElementByLinkText(string linkText);
        public IWebElement FindElementByName(string name);
        public IWebElement FindElementByPartialLinkText(string partialLinkText);
        public IWebElement FindElementByTagName(string tagName);
        public IWebElement FindElementByXPath(string xpath);
        public ReadOnlyCollection<IWebElement> FindElements(By by);
        protected ReadOnlyCollection<IWebElement> FindElements(string mechanism, string value);
        public ReadOnlyCollection<IWebElement> FindElementsByClassName(string className);
        public ReadOnlyCollection<IWebElement> FindElementsByCssSelector(string cssSelector);
        public ReadOnlyCollection<IWebElement> FindElementsById(string id);
        public ReadOnlyCollection<IWebElement> FindElementsByLinkText(string linkText);
        public ReadOnlyCollection<IWebElement> FindElementsByName(string name);
        public ReadOnlyCollection<IWebElement> FindElementsByPartialLinkText(string partialLinkText);
        public ReadOnlyCollection<IWebElement> FindElementsByTagName(string tagName);
        public ReadOnlyCollection<IWebElement> FindElementsByXPath(string xpath);
        public Screenshot GetScreenshot();
        public IOptions Manage();
        public INavigation Navigate();
        public void Quit();
        protected virtual void StartClient();
        protected void StartSession(ICapabilities desiredCapabilities);
        protected virtual void StopClient();
        public ITargetLocator SwitchTo();
    }

Gdzie to mnie najbardziej interesuje


        // Dla pojedyńczego elementu
        public IWebElement FindElement(By by);
        protected IWebElement FindElement(string mechanism, string value);
        public IWebElement FindElementByClassName(string className);
        public IWebElement FindElementByCssSelector(string cssSelector);
        public IWebElement FindElementById(string id);
        public IWebElement FindElementByLinkText(string linkText);
        public IWebElement FindElementByName(string name);
        public IWebElement FindElementByPartialLinkText(string partialLinkText);
        public IWebElement FindElementByTagName(string tagName);
        public IWebElement FindElementByXPath(string xpath);


        // Dla list
        public ReadOnlyCollection<IWebElement> FindElements(By by);
        protected ReadOnlyCollection<IWebElement> FindElements(string mechanism, string value);
        public ReadOnlyCollection<IWebElement> FindElementsByClassName(string className);
        public ReadOnlyCollection<IWebElement> FindElementsByCssSelector(string cssSelector);
        public ReadOnlyCollection<IWebElement> FindElementsById(string id);
        public ReadOnlyCollection<IWebElement> FindElementsByLinkText(string linkText);
        public ReadOnlyCollection<IWebElement> FindElementsByName(string name);
        public ReadOnlyCollection<IWebElement> FindElementsByPartialLinkText(string partialLinkText);
        public ReadOnlyCollection<IWebElement> FindElementsByTagName(string tagName);
        public ReadOnlyCollection<IWebElement> FindElementsByXPath(string xpath);

 

a tak wygląda IWebDriver

string CurrentWindowHandle { get; }
        string PageSource { get; }
        string Title { get; }
        string Url { get; set; }
        ReadOnlyCollection<string> WindowHandles { get; }

        void Close();
        IOptions Manage();
        INavigation Navigate();
        void Quit();
        ITargetLocator SwitchTo();
 

Był bym wdzięczny jak ktoś by mi pomógł to zrozumieć oraz posklecać pod siebie ;)

0

Więc tak zrobiłem coś takiego do przetestowania i uruchomiłem testy by sobie sprawdzić jak to sobie idzie oraz w jakiej kolejności, nazwy nie są odpowiednie bo na razie testuje sobie jak to działa

Test

 
[TestFixture]
    public class Class1
    {
        [TestCase]
        public void testc()
        {
            var fooService = new TestRepo();

            var fooelement = fooService.GetSample(By.IdAndRange(1, 50)); // <- Tutaj wylatuje wyjątek tą samą strzałką potem oznaczę gdzie to jest powiązane
            fooelement = fooService.GetSample(By.TimeRange(new DateTime(1990, 11, 20), new DateTime(1990, 11, 20)));
        }
    }

Raczej nie service tylko FekRepozitory to wrzuciłem z racji iż tutaj nie namieszam zbyt wiele docelowo ma to być do serwisu a repozitory ma wyciągać dane z DB ale to całkiem inna bajeczka

O dziwo myślałem iż tutaj się od razu odwołam do public ReadOnlyCollection<ISampleStamp> GetSample(By by) i polecę w duł lecz ku zdziwieniu nie

 

namespace SampleDB.FaekRepozitory
{
    public class TestRepo : ISearchContext
    {

        public ReadOnlyCollection<ISampleStamp> GetSample(By by)
        {
            throw new NotImplementedException();
        }

        protected ReadOnlyCollection<ISampleStamp> GetSample(string mechanism, string value)
        {
            throw new NotImplementedException();
        }

        public ReadOnlyCollection<ISampleStamp> GetSampleByIdAndRange(int idToFind, int Range)
        {
            throw new NotImplementedException();
        }
        
        public ReadOnlyCollection<ISampleStamp> GetSampleByTimeRange(DateTime startTime, DateTime endTime)
        {
            throw new NotImplementedException();
        }
    }
}

Tutaj nie ma zbyt wielkiej filozofia tłumaczenia

 
  public interface ISearchContext
    {
        ReadOnlyCollection<ISampleStamp> GetSample(By by);
    }

Teraz tak IWebElement podmieniłem na ISampleStamp tylko się tak kurde zastanawiam po cholerę ISampleStamp ogólnie będę bazował na kolekcji SampleStamp i takie kolekcje dalej wywalał. Ogólnie na samym końcu jak wyjdzie to z warstwy serwisowej to program będzie to jeszcze dalej wypluwał w Postaci JSON'a nie wiem czy tutaj coś kombinować ISampleStamp dałem tylko dla tego żeby się już trzymać I ;) tak jak tamci to zrobili

public interface ISampleStamp
    { }

    public class SampleStamp : ISampleStamp
    {
        public int Id { get; set; }
        public DateTime DateStamp { get; set; }
        public List<SampleValue> Data { get; set; }

        public SampleStamp() { }
        public SampleStamp(int id, DateTime dateStamp, List<SampleValue> data)
        {
            this.Id = id;
            this.DateStamp = dateStamp;
            this.Data = data;
        }

    }


    public class SampleValue
    {
        public string Name { get; set; }
        public decimal Value { get; set; }

        public SampleValue() { }
        public SampleValue( string name, decimal value)
        {
            this.Name = name;
            this.Value = value;
        }
    }
 

Teraz klasa By wykasowałem w niej wszystko to co myślę iż jest nie potrzebne i zrobiłem tak żeby skompilować

 
[Serializable]
    public class By
    {
        protected By(){}
        protected By(Func<ISearchContext, ReadOnlyCollection<ISampleStamp>> GetSampleMethod) { }

        public override bool Equals(object obj) { throw new NotImplementedException(); }
        
        public static bool operator !=(By one, By two) { throw new NotImplementedException(); }
        public static bool operator ==(By one, By two) { throw new NotImplementedException(); }

        protected Func<ISearchContext, ReadOnlyCollection<ISampleStamp>> GetSampleMethod 
        {
            get;
            set; 
        }

        public virtual ReadOnlyCollection<ISampleStamp> GetSample(ISearchContext context) 
        { 
            throw new NotImplementedException();
        }

        public static By IdAndRange(int idToFind, int Range) { throw new NotImplementedException(); } // <- Ku mojemu zdziwieniu od razu tutaj wskoczyło 
        public static By TimeRange(DateTime startTime, DateTime endTime) { throw new NotImplementedException(); }
        
        public override string ToString() { throw new NotImplementedException(); }
        
    }

Teraz moje pytanie chyba największe
public static By IdAndRange(int idToFind, int Range) { throw new NotImplementedException(); } //

Co to kurde ma zwracać ? ^^

0

https://seleniumhq.github.io/selenium/docs/api/dotnet/

Dokumentacja i jest tutaj opis klasy By

0

Małe odkrycie

public static By IdAndRange(int idToFind, int Range) 
        {
            return new By();
        }

wrzuci mnie do

protected By(){}

a to mnie przeniesie do tylko żę by jest puste ;)

public ReadOnlyCollection<ISampleStamp> GetSample(By by)
        {
            throw new NotImplementedException();
        }
 

troszkę już jestem bliżej w rozwiązaniu tego bajeru ;)

teraz muszę coś wykombinować jak to wrzucić do tego i co to ma jeszcze zrobić :>>>>>

protected By(Func<ISearchContext, ReadOnlyCollection<ISampleStamp>> GetSampleMethod) { }

obstawiam iż to ma wywoałc w takiej kolejności

 {
            get;
            set; 
        }

        public virtual ReadOnlyCollection<ISampleStamp> GetSample(ISearchContext context) 
        { 
            throw new NotImplementedException();
        }

ale co dalej to nie mam pojęcia

0

Ok mam rozwiązanie które mnie zadowala ;) i By działa tak jak chciałem

Przykład odpalenia na debugger iż zwraca to co chcę

 
[TestFixture]
    public class SampleDataTest
    {
        [TestCase]
        public void TEEEEE()
        {
            var Service = new Test();
            Service.Get(By.Id(1));
        }
    }

Niekompletna budowa klasy wyszukiwania By

 
public class By
    {
        protected By()
        { }

        public static By Id(int id)
        {
            return new ById(id);
        }

        public static By Name(string name)
        {
            throw new NotImplementedException();//return name;
        }
    }

    public class ById : By
    {
        public int Id;

        public ById(int id)
        {
            this.Id = id;
        }
    }

A tutaj wywołanie

 
 public class Test :  ISearchContext
    {
        public SampleStamp Get(By by)
        {
            // <-- Implementujemy coś takiego jak jeszcze niżej
            var te = by; // <- przyjmuje budowę klasy ByID
            return new SampleStamp();
        
        }

    }

             if (by is ById) // Rozpoznajemy dzięki temu jaką metodą mamy wyszukiwać
            {

                var byId = (by as ById);
            }
 
0

Ok mam rozwiązanie które mnie zadowala ;) i By działa tak jak chciałem

Przykład odpalenia na debugger iż zwraca to co chcę

 
[TestFixture]
    public class SampleDataTest
    {
        [TestCase]
        public void TEEEEE()
        {
            var Service = new Test();
            Service.Get(By.Id(1));
        }
    }

Niekompletna budowa klasy wyszukiwania By

 
public class By
    {
        protected By()
        { }

        public static By Id(int id)
        {
            return new ById(id);
        }

        public static By Name(string name)
        {
            throw new NotImplementedException();//return name;
        }
    }

    public class ById : By
    {
        public int Id;

        public ById(int id)
        {
            this.Id = id;
        }
    }

A tutaj wywołanie

 
 public class Test :  ISearchContext
    {
        public SampleStamp Get(By by)
        {
            // <-- Implementujemy coś takiego jak jeszcze niżej
            var te = by; // <- przyjmuje budowę klasy ByID
            return new SampleStamp();
        
        }

    }

             if (by is ById) // Rozpoznajemy dzięki temu jaką metodą mamy wyszukiwać
            {
                // <- tutaj implementujemy co ma się zdarzyć 
                var byId = (by as ById); // <- a tak zmieniamy nasze by z typu By na ById i potrafimy wszystko wyciągnąć lecz ja bym to zrobił tak 
            }

.......

            if (by is ById) // Rozpoznajemy dzięki temu jaką metodą mamy wyszukiwać
            {
                GetById(by); 
            }

            private object GetById(By by)
            {
                     var byId = (by as ById);
                     // Do something and return
            }
 

powinno zadziałać, dzięki temu myślę iż będzie jeszcze łatwiej się posługiwać oraz wywoływać jedną metodę która zwraca ten sam object lecz pod rożnymi kryteriami wyszukiwania.

0

Skąd wiesz, że działa, skoro w teście nie masz żadnych asercji?

0

test jest nie pełny ;) to co napisąłem też jest nie pełne bo funkcja przecież musi coś zwrócić a ja sobie ją wywołałem jak voida.

Lecz test zrobiłem tobie na debugerce i podejrzałem by jakie wartości mi zwraca ;P to mi styknie, teraz zrobię faek repo i będę je testował na razie najważniejsze jest i przechodzę

na razie debugerka leci na podglądzie i tak to wygląda

 [TestFixture]
    public class SampleDataTest
    {
        [TestCase]
        public void TEEEEE()
        {
            var test = new FaekSampleRepozitory();
            var ba = test.GetSample(By.IdAndRange(10, 11));
        }
    }
 
 
public class FaekSampleRepozitory 
    {
        public List<SampleStamp> GetSample(By by)
        {
           if (by is ByCurrentAndRange)
           {
               return GetSampleByCurrentAndRange(by);
           }
           else if (by is ByIdRange)
           {
               return GetSampleByIdRange(by);
           }
           else if (by is ByIdAndRange)
           {
               return GetSampleByIdAndRange(by);
           }
           else if (by is ByTimeRange)
           {
               return GetSampleByTimeRange(by);
           }
           else if (by is ByTimeAndRange)
           {
               return GetSampleByTimeAndRange(by);
           }
           throw new NotImplementedException();

        }
        
        
        private List<SampleStamp> GetSampleByCurrentAndRange(By by)
        {
            throw new NotImplementedException();
        }

        private List<SampleStamp> GetSampleByIdRange(By by)
        {
            throw new NotImplementedException();
        }

        private List<SampleStamp> GetSampleByIdAndRange(By by)
        {
            throw new NotImplementedException();
        }

        private List<SampleStamp> GetSampleByTimeRange(By by)
        {
            throw new NotImplementedException();
        }

        private List<SampleStamp> GetSampleByTimeAndRange(By by)
        {
            throw new NotImplementedException();
        }

        
    }

I spokojnie tutaj mi wywala wyjątek ;)

 private List<SampleStamp> GetSampleByIdAndRange(By by)
        {
            throw new NotImplementedException();
        }
 

Więc dla mnie jest cacy o to mi właśnie chodziło Wywoływanie metody jest teraz bardzo przyjemne

0

Ok działa i przeszło na razie trywialny test ale jest ;) i dla jednej metody ale całość działa więc jestem dobrej myśli

 [TestCase(20,10)]
        [TestCase(21, 10)]
        [TestCase(21, 9)]
        [TestCase(20, 9)]
        public void IdAndRangeTest(int id, int range)
        {
            // arrange
            var repo = new FaekSampleRepozitory();


            // act 
            var result = repo.GetSample(By.IdAndRange(id, range));

            //assert
            Assert.IsNotNull(result);
            Assert.IsTrue(result.Count() == ((range *2) + 1));
        }
 

testowana metoda

 
 private List<SampleStamp> GetSampleByIdAndRange(By by)
        {
            var criteria = (by as ByIdAndRange);
            return samples.FindAll(x => (x.Id >= (criteria.Id - criteria.Range)) & (x.Id <= (criteria.Id + criteria.Range)));
        }

I teraz feak repo na którym się bawim wygląda jak wygląda bo niechce mi się tego ręcznie pisać a lepszej koncepcji stworzenia nie miałem, ważne żę mamy jakieś dane i odstępny są w nich co jedną sec a kolekcja ma 1000 sampli z róznymi wartościami

 
private readonly static List<SampleStamp> samples = CreateSamplesListDynamic().ToList();

        private static List<string> valueName;
        
        
        private static List<SampleStamp> CreateSamplesListDynamic()
        {

            valueName = new List<string>() {"Value1","Value2","Value3","Value4","Value5","Value6"};
            Random random = new Random();
            
            List<SampleStamp>  returnSamples = new List<SampleStamp>(); 
            
            for (int i = 0; i < 1000; i++)
            {
                returnSamples.Add(new SampleStamp(i + 1, DateTime.Now.AddSeconds(-i), CreateSampleValue(random)));
            }

            return returnSamples;
        }

        private static List<SampleValue> CreateSampleValue(Random random)
        {
            List<SampleValue> samplesValues = new List<SampleValue>();
            
           
            
            foreach(var value in valueName)
            {
                decimal dec =  Convert.ToDecimal(Math.Round(((random.NextDouble() + 1) / 100), 3));
                samplesValues.Add(new SampleValue(value, dec));
            }

            return samplesValues;
        }
0

Jedna sprawa mnie tylko martwi w tym wszystkim jestem wstanie stworzyć
var test = By.IdRange(1, 1); i to przejdzie ;/ Jak jestem wstanie to zabezpieczyć żeby takiego wywołania się nie dało zrobić :>

0

Sprawdź wartości podane do By.IdRange i rzuć wyjątkiem.
A potem przepisz ten kod na wersję obiektową - tak, aby użyć polimorfizmu zamiast tych wszystkich is.

0

Nie wiem o co Ci chodzi z tym wyjątkiem, ale używanie polimorfizmu jest totalnym idiotyzmem w tym przypadku dla czego.

zaczerpnięte

 
public class Shape
{
    // A few example members
    public int X { get; private set; }
    public int Y { get; private set; }
    public int Height { get; set; }
    public int Width { get; set; }

    // Virtual method
    public virtual void Draw()
    {
        Console.WriteLine("Performing base class drawing tasks");
    }
}

class Circle : Shape
{
    public override void Draw()
    {
        // Code to draw a circle...
        Console.WriteLine("Drawing a circle");
        base.Draw();
    }
}

Tak wywołujemy

 
class Program
{
    static void Main(string[] args)
    {
        // Polymorphism at work #1: a Rectangle, Triangle and Circle
        // can all be used whereever a Shape is expected. No cast is
        // required because an implicit conversion exists from a derived 
        // class to its base class.
        System.Collections.Generic.List<Shape> shapes = new System.Collections.Generic.List<Shape>();
        shapes.Add(new Rectangle());
        shapes.Add(new Triangle());
        shapes.Add(new Circle());

        // Polymorphism at work #2: the virtual method Draw is
        // invoked on each of the derived classes, not the base class.
        foreach (Shape s in shapes)
        {
            s.Draw();
        }

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

}

Mój przykładowy kod

public List<SampleStamp> GetSample(By by)
        {
           if (by is ByIdRange)
           {
               return GetSampleByIdRange(by);
           }
           else if (by is ByTimeRange)
           {
               return GetSampleByTimeRange(by);
           }
           throw new NotImplementedException();

        }
 

Wywoływał by

public List<SampleStamp> GetSample(By by)
        {
           
               return by.Get();
        }
 

Przez co klasa By albo raczej klasy dziedziczące musiały by mieć w kodzie nadpisanej funkcji Get pełną implementację czegoś takiego

private List<SampleStamp> GetSampleByIdRange(By by)
        {
            var criteria = (by as ByIdRange);
            return samples.FindAll(x => (x.Id >= criteria.StartId) & (x.Id <= criteria.EndId));
        
        }

Z jednej strony nie jest to głupie ale takiego rozwiązania nie jesteśmy wstanie zaimplementować w większości projektach, co za tym idzie do każdego repo czy do każdego servisu musimy pisać to na nowo.

Chyba że jest coś o czym nie wiem. Np teraz chce to wykożystać do feakrepo gdzie działam na liście nastepnie będzie chdział to zaimplementować do repo pobierającym dane z sql a jeszcze dalej podpiąć następne które będzie bazowało na MongoDB

Jak pokażesz mi jak to zrobić uniwersalnie tak żeby w każdej klasie repozitory inaczej się zachowywało to będę wdzięczny. Bo nie mam na to pomysłu żeby zrobić to uniwersalnie oraz w miarę prosto.

3
Bardzo mały lew napisał(a):

używanie polimorfizmu jest totalnym idiotyzmem w tym przypadku dla czego.

Bardzo mocne stwierdzenie jak na kogoś, kto nie zna takich podstawowych podstaw jak rzucanie wyjątków. ;]

ByIdRange(int min, int max)
{
    if (min >= max)
        throw new InvalidArgumentException("min ma być mniejszy od max");
    // reszta kodu
}

__W ogólności: __

  1. Klasa bazowa nie powinna znać swoich typów pochodnych. Jeśli ktoś stosuje odwołania do klas pochodnych w klasie bazowej, to łamie zasady SRP, OCP, LSP i serce swojej matki. To nie jest kwestia poglądów czy technologii, to jest po prostu elementarne i nie podlega dyskusji. W OOP nie da się bardziej spieprzyć kodu niż tworząc takie powiązanie. (Tak, wiem że już tego w kodzie nie masz, ale miałeś, dlatego przestrzegam.)

  2. Przyjmowanie obiektu typu bazowego, a potem sprawdzanie jaki jest jego konkretny typ i przekierowanie przepływu programu też nie jest ok. Owszem, robi się tak, ale zawsze lepiej tego uniknąć. Im mniej ifologi w kodzie tym lepiej, a ifologia oparta na typach jest najgorsza. W przypadku dodania nowego sposobu filtrowania musisz zmienić znacznie więcej miejsc, niż gdybyś tej ifologii nie miał.

Co do Twojego kodu:

Nie ma najmniejszego sensu, żeby klasy defniujące poszczególne rodzaje filtrowania dziedziczyły z klasy By, bo nie dostarcza ona im żadnej bazowej funkcjonalności ani danych. By to zbiór statycznych metod stanowiących pewien cukier składniowy, klasy z niej dziedziczące dostarczają dane do filtrowania. To dwa zupełnie różne światy.

Gdy pisałem o polimorfizmie chodziło mi o coś mniej więcej takiego:

public abstract class Criteria<T>
{
    public abstract List<T> Filter(List<T> list);
}

public class IdAndRangeCriteria : Criteria<SampleStamp>
{
    public int Id { get; private set; }
    public int Range { get; private set; }

    public IdAndRangeCriteria(int id, int range)
    {
        this.Id = id;
        this.Range = range;
    }

    public override List<SampleStamp> Filter(List<SampleStamp> list)
    {
        return list.FindAll(x => (x.Id >= this.Id - this.Range) && (x.Id <= this.Id + this.Range));
    }
}

public interface ISearchContext<T>
{
    IList<T> GetSample(Criteria<T> criteria);
}

public class FaekSampleRepozitory : ISearchContext<SampleStamp>
{
    public IList<SampleStamp> GetSample(Criteria<SampleStamp> criteria)
    {
        return criteria.Filter(samples);
    }
}

Jak widać - żadnych ifów, a dodanie nowego sposobu filtrowania nie wymaga zmiany kodu klasy "repozytorium", ani istniejących klas bazowych. Do tego klasy nie rozrastają się do chorych rozmiarów.

No, ale jak rozumiem Tobie się to nie podoba. Nie rozumiem za to, czemu dla Ciebie to jest złe:

public class JakisService
{
void GetFooById(int id)
void GetFooByValue(int value)
void GetFooByName(string name )
...
}

a to dobre:

public class FaekSampleRepozitory 
    {
        public List<SampleStamp> GetSample(By by)
        {
           if (by is ByCurrentAndRange)
           {
               return GetSampleByCurrentAndRange(by);
           }
           else if (by is ByIdRange)
           {
               return GetSampleByIdRange(by);
           }
           else if (by is ByIdAndRange)
           {
               return GetSampleByIdAndRange(by);
           }
           else if (by is ByTimeRange)
           {
               return GetSampleByTimeRange(by);
           }
           else if (by is ByTimeAndRange)
           {
               return GetSampleByTimeAndRange(by);
           }
           throw new NotImplementedException();
 
        }
 
 
        private List<SampleStamp> GetSampleByCurrentAndRange(By by)
        {
            throw new NotImplementedException();
        }
 
        private List<SampleStamp> GetSampleByIdRange(By by)
        {
            throw new NotImplementedException();
        }
 
        private List<SampleStamp> GetSampleByIdAndRange(By by)
        {
            throw new NotImplementedException();
        }
 
        private List<SampleStamp> GetSampleByTimeRange(By by)
        {
            throw new NotImplementedException();
        }
 
        private List<SampleStamp> GetSampleByTimeAndRange(By by)
        {
            throw new NotImplementedException();
        }
 
 
    }

Czyli zastąpiłeś klasę z n metod publicznych poprzez klasę z 1 metodą publiczna + n metod prywatnych. W ten sposób tylko zwiększasz ilość kodu, a do tego wprowadzasz ifologie. Już lepiej byłoby mieć np. tak zdefiniowany interfejs:

public interface ISearchContext<T>
{
    IList<T> GetSample(ById criteria);
    IList<T> GetSample(ByIdAndRange criteria);
    IList<T> GetSample(ByName criteria);
   ...
}

Przynajmniej nie trzeba się zastanawiać, co jest możliwe, a co nie, bo masz jasno zdefiniowane API.

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