none
How to get the property from a string and make the compiler regonize that is a property and not a string RRS feed

  • Question

  • I have a code, that I will filter things from the db, but I don't want to repeat the same line of code and only change the filter.
    So, I want to make a function with a parameter... And when I need to change I will just in one place (as a clean code has to be).

    string filter= string.Empty;
                filter= cbFilter.SelectedItem.ToString();
                string textToFilter=string.Empty;
                textToFilter=txtFilter.Text;
                switch (filter)
                {
    
                    case "Name":
                   var books= from b in book.GetAll() where b.Name == textToFilter select b;
                        break;
    
                    case "Title":
    
                  //same here
                        break;
    
                    case "Format":
                 //same here
                        break;
    
                    case "Category":
                 //same here
                        break;
    
                    case "Type":
                 //same here
                        break;
    
    
                    default:
                        MessageBox.Show("Error", "wrong filter", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        break;
                }


    So I want to avoid all that, I know that sometimes repeat is not optional.
    Doing something like this:
      private IEnumerable<DTOBook>FilteredBook(string filter, string property)
            {
             return var b= from b in book.GetAll() where b.property == filter select b;
            }

    Is is possible with short and easy code to make the b recognize the property as one of his properties and not a string?

    PS: There's probably errors in the code above, the point is to you guys understand enough to help, so I won't try to make it 100% good.
    Thanks :)

    BP-LP 2005/2016 @ll rights reserved



    Monday, January 28, 2019 7:34 AM

Answers

  • @Belarmino Vicenzo

    ...

    Doing something like this:

      private IEnumerable<DTOBook>FilteredBook(string filter, string property)
            {
             return var b= from b in book.GetAll() where b.property == filter select b;
            }


    Is is possible with short and easy code to make the b recognize the property as one of his properties and not a string?

    Yes, it's possible and it requires just a little bit of code.

    First, let's refactor the code quoted above:

    private IEnumerable<Book> FilteredBooks(string propertyName, string propertyValue)
    {
        return 
                from book in AllBooks 
                where book.Match(propertyName, propertyValue)
                select book
                ;
    }

    Notice that I changed some names...

    The string propertyName could be something like Title, and the string  propertyValue could be The Big Bang.

    I also added a method named Match, that must be added; you have some options, but I recommend this one: extension method.

    For instance, you could implement it this way:

    public static class BookXt{
        public static bool Match(this Book book,string propName,string propValue){
            switch(propName){
                case nameof(book.Name):return book.Name==propValue;
                case nameof(book.Title):return book.Title==propValue;
                case nameof(book.Year):return book.Year.ToString()==propValue;
                default:return false;
            }
        }
    }
    

    As you see, it's simple.

    Tuesday, January 29, 2019 4:23 AM

All replies

  • Quite a few different ways to solve this depending upon how flexible you want to be and how often things change. In my experience the odds of you changing something like this is small because it would involve a DB change if you wanted to keep your C# name in sync. But if this is really a concern then why not just do dynamic SQL where you pull the column names (for your listbox) from the schema of the table?

    Ignoring the DB aspect you can simply use a Where clause to clean this up pretty quick.

    var query = book.GetAll();
    
    //Ignoring case here
    switch (filter)
    {
       case "Name": query.Where(p => p.Name == textToFilter); break;
       case "Title": ...
    };

    You could take this a step further and use the Tag property of the listbox to associate the action to perform when the item is selected. As an example.

    public abstract class QueryCriteria
    {
       public abstract IQueryable<MyData> Apply ( IQueryable<MyData> query );
    }
    
    public class NameQueryCriteria : QueryCriteria
    {
       public string Filter { get; set; }
    
       public override IQueryable<MyData> Apply ( IQueryable<MyData> query )
       {
          return query.Where(x = > x.Name == filter);
       }
    }

    Now when you add the item to the listbox you set the Tag to the criteria you want. When running the query you get the tag, cast as the criteria and apply it. This is probably overkill for simply trying to get rid of some strings but it expands really well to more complex queries.

    Finally, since it appears you might be using EF, you could also just rely on the underlying property name that is already available and the nameof operator.

    switch (filter)
    {
       case nameof(MyData.Name): ...
    };
    The advantage of this approach is that if you do rename the column in the DB then you'll likely rename the corresponding .NET type. When you symbolically rename that then it'll find the nameof references as well.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, January 28, 2019 4:54 PM
    Moderator
  • @Belarmino Vicenzo

    ...

    Doing something like this:

      private IEnumerable<DTOBook>FilteredBook(string filter, string property)
            {
             return var b= from b in book.GetAll() where b.property == filter select b;
            }


    Is is possible with short and easy code to make the b recognize the property as one of his properties and not a string?

    Yes, it's possible and it requires just a little bit of code.

    First, let's refactor the code quoted above:

    private IEnumerable<Book> FilteredBooks(string propertyName, string propertyValue)
    {
        return 
                from book in AllBooks 
                where book.Match(propertyName, propertyValue)
                select book
                ;
    }

    Notice that I changed some names...

    The string propertyName could be something like Title, and the string  propertyValue could be The Big Bang.

    I also added a method named Match, that must be added; you have some options, but I recommend this one: extension method.

    For instance, you could implement it this way:

    public static class BookXt{
        public static bool Match(this Book book,string propName,string propValue){
            switch(propName){
                case nameof(book.Name):return book.Name==propValue;
                case nameof(book.Title):return book.Title==propValue;
                case nameof(book.Year):return book.Year.ToString()==propValue;
                default:return false;
            }
        }
    }
    

    As you see, it's simple.

    Tuesday, January 29, 2019 4:23 AM
  • @Belarmino Vicenzo

    ...

    Doing something like this:

      private IEnumerable<DTOBook>FilteredBook(string filter, string property)
            {
             return var b= from b in book.GetAll() where b.property == filter select b;
            }


    Is is possible with short and easy code to make the b recognize the property as one of his properties and not a string?

    Yes, it's possible and it requires just a little bit of code.

    First, let's refactor the code quoted above:

    private IEnumerable<Book> FilteredBooks(string propertyName, string propertyValue)
    {
        return 
                from book in AllBooks 
                where book.Match(propertyName, propertyValue)
                select book
                ;
    }

    Notice that I changed some names...

    The string propertyName could be something like Title, and the string  propertyValue could be The Big Bang.

    I also added a method named Match, that must be added; you have some options, but I recommend this one: extension method.

    For instance, you could implement it this way:

    public static class BookXt{
        public static bool Match(this Book book,string propName,string propValue){
            switch(propName){
                case nameof(book.Name):return book.Name==propValue;
                case nameof(book.Title):return book.Title==propValue;
                case nameof(book.Year):return book.Year.ToString()==propValue;
                default:return false;
            }
        }
    }

    As you see, it's simple.

    I also refactor your code a little bit, and it's what I wanted.

    private string FilteredBook(string propName, string propValue)
            {
                var books= book.ObterTodos();
    
                foreach (var book in books)
                {
                    switch (propName)
                    {
            case nameof(book.Name):
    
                 var x = FilteredBooks("Name", propValue);
               return   (from b in x select b.Name).First();
    
                             
    
    
            case nameof(book.Title):
              var y = FilteredBooks("Title", propValue);
              return (from b in y select b.Title).First();
    
    
            case nameof(book.Year):
              var z = FilteredBooks("Year", propValue);
              return (from b in z select b.Year).First();
    
                        default: break;
                    }
                }
    
                return "";
            }
    
        private IEnumerable<DTOBook> FilteredBooks(string propName, string propValue)
            {
              return
                    from book in books.GetAll()
                    where book.Match(propName, propValue)
                     select book
                        ;
    
            }
    
            // tested on the main, and it worked :) 
           var x = FilteredBooks("Title", textToBeFiltered);
                 
    
                MessageBox.Show(x);
     

    Well, that's working, I still need to change the var names to improve readability.

    I would like to create a local function, but my colleague is using VS12 and I'm after him to install at least VS15, but both still won't support that.

    Anyway.. 

    I'm planning to remove the extension method, since I'm repeating the "propName" and "propValue", I think I can refactor and put the extension code to the FilteredBooks function.

    Now, Should I keep with your code (it's very understandable and clean) or my adaptation is okay?


    BP-LP 2005/2016 @ll rights reserved


    Tuesday, January 29, 2019 8:08 AM
  • Hi Belarmino,

    I suggest that It is best for you to keep you code.

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Thursday, January 31, 2019 6:54 AM
    Moderator