-1

Suppose I have a class like this:

    public class DepartmentBase<T> : MyBase where T : new()
    {
        public ObservableCollection<T> Employees
        {
           get { return _employees; }
           set { _employees = value; OnPropertyChanged(); }
        }
        private ObservableCollection<T> _employees;
    
        public T Selected_employee
        {
            get { return _selected_employee; }
            set { _selected_employee = value; OnPropertyChanged(); }
        }
        private T _selected_employee;
        
        public void AddEmployee(object parameter)
        { 
           //Using dynamic - each type T has those 3 properties        
           dynamic new_employee = new T();
           new_employee.NEW = true;
           new_employee.START_DATE = DateTime.Now;
    
           Employees.Add(new_employee);
           
           //Using reflection with Read() and Set() methods, to set each T item property "NEW" to false
           Employees.Where(a => (bool)a.Read("NEW") == true).ToList().ForEach(b => b.Set("NEW", false));
    
           Selected_employee = Employees.Last();
        }
    }

As you see, void AddEmployees needs to directly handle with properties of type T in 2 different ways.

In first lines I add items to Collection, using dynamic keyword. This enables me to write code like that.

After that I'm using Linq on Collection, where certain properties meets criteria. For that I use reflection.

Both ways are resolved in run-time (as I am aware of), which has performance hits.

My question is: How to access properties in generic class in a way that I could write code as with dynamic keyword, but also work same way with Linq and keep everything anonymous so that code resolves at compile time?

ASh
  • 34,632
  • 9
  • 60
  • 82
Lucy82
  • 654
  • 2
  • 12
  • 32
  • 1
    These are conflicting requirements. Generics is for things known at compiletime if you only know them at runtime its not generic but dynamic. If your class expects that T has a NEW and START_DATE property then let the classes used as T implement an interface having that properties and make a generic type constraint on that interface. Then your back at safe generic code checkable at compiletime and LINQ works against that interface. – Ralf Apr 13 '23 at 13:17
  • @Ralf I understand you a bit but not completely, could you post an example? – Lucy82 Apr 13 '23 at 13:22

1 Answers1

2

How to access properties in generic class in a way that I could write code as with dynamic keyword, but also work same way with Linq and keep everything anonymous so that code resolves at compile time?

By adding a constraint on the type parameter:

public class DepartmentBase<T> : MyBase where T : IModel, new()
{
    public ObservableCollection<T> Employees
    {
        get { return _employees; }
        set { _employees = value; OnPropertyChanged(); }
    }
    private ObservableCollection<T> _employees;

    public T Selected_employee
    {
        get { return _selected_employee; }
        set { _selected_employee = value; OnPropertyChanged(); }
    }
    private T _selected_employee;

    public void AddEmployee(object parameter)
    {
        T new_employee = new T();
        new_employee.NEW = true;
        new_employee.START_DATE = DateTime.Now;

        Employees.Add(new_employee);

        //Using reflection with Read() and Set() methods, to set each T item property "NEW" to false
        Employees.Where(a => (bool)a.Read("NEW") == true).ToList().ForEach(b => b.Set("NEW", false));

        Selected_employee = Employees.Last();
    }
}

IModel is an interface (or class) that any type that you use with DepartmentBase<T> must implement:

public interface IModel
{
    bool NEW { get; set; }
    DateTime START_DATE { get; set; }

    bool? Read(string s);
    void Set(string s, bool b);
}
mm8
  • 163,881
  • 10
  • 57
  • 88
  • 2
    I assume the Read method was just some "vehicle" to show us where he struggles getting the NEW property in his LINQ statement. Now that you fixed it the LINQ Statement can simply use the NEW Property. – Ralf Apr 13 '23 at 13:50
  • 1
    @mm8, jesus christ, this is what I tried in first place, when reading other posts. But your last sentence "**that any type that you use with DepartmentBase must implement**" nailed It down for me. I was doing that in wrong place - I implemented interface on class that inherits **DepartmentBase**, instead on **type** !!...Thanks a lot !!! BTW- Read and Set not needed, Linq works same without that (on same properties via interface though) :) – Lucy82 Apr 13 '23 at 13:51
  • @Ralf: True. I obviously didn't read the code in the question good enough to figure that out myself:) – mm8 Apr 13 '23 at 13:53
  • @mm8, just out of curiousity - are there any other better ways to handle situations like this or is this the only proper way ? Not that I don't like It - It's neat solution. – Lucy82 Apr 13 '23 at 13:56
  • 1
    For a generic type with a type parameter `T`, using a constraint on `T` is the proper way if you want to be able to do something "specific" with the instance of the type `T`, such as for example setting or comparing a property. – mm8 Apr 13 '23 at 13:59
  • 1
    The other option is to skip the generics and compile-time safety and instead use a common base type such as `object` and then try to cast the parameter at runtime. – mm8 Apr 13 '23 at 14:01