lundi 27 février 2023

C# upcasting object - best practice or pattern

I am stumbling over a simple problem for years now and I'm not sure if I missed a good feature of C# or a pattern which could help out.

Imaging a simple class Person which only has 2 properties - string FirstName and string LastName. This could either be your own class in own libs or a third party lib. Now you want to use a grid and display the Person's, so that a user can select multiple persons via checkboxes in the grid. So we are creating a PersonsSelectable class, which inherits from Person and gets a new property "bool Selected". Are there any way's or patterns which would allow me to use the already created Person objects to create PersonsSelectable objects?

Please note, that I broke down the problem to a very simple class and a very specific example. Normaly the classes are way more complex and the problem is not limited to select objects in a grid.

There could be multiple way's to solve this, but I think all of the way's I know are messy (but simple). They either produce large amound's of boilerplate code or they are prone to error.

  1. Way - just copy the properties
    internal static class Program
    {
        [STAThread]
        static void Main()
        {
            Person person = new Person() { FirstName = "Testi", LastName = "McTestincton" };
            PersonSelectable selectable = new PersonSelectable();
            selectable.ReadData(person);
        }
    }

    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        // Could also be an extension method
        public void ReadData(Person person)
        {
            FirstName = person.FirstName;
            LastName = person.LastName;
        }
    }

    public class PersonSelectable : Person
    {
        public bool Selected { get; set; }
    }

This way is prone to error, because if you get an update of the lib, the class Person may get new properties, which will not be copied (which could be fatal in db applications).

  1. proxy/decorator etc.
    internal static class Program
    {
        [STAThread]
        static void Main()
        {
            Person person = new Person() { FirstName = "Testi", LastName = "McTestincton" };
            PersonSelectable selectable = new PersonSelectable(person);
        }
    }

    public interface IPerson
    {
        string FirstName { get; set; }
        string LastName { get; set; }
    }

    public class Person : IPerson
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public class PersonSelectable : IPerson
    {
        protected IPerson Person { get; set; }
        public bool Selected { get; set; }
        public string FirstName { get => Person.FirstName; set => Person.FirstName = value; }
        public string LastName { get => Person.LastName; set => Person.LastName = value; }

        public PersonSelectable(IPerson person)
        { Person = person; }
    }

Produces way to much boilerplate code in complex classes. It would be really nice if you could define the "over" implementation more implicit like "public class PersonSelectable : IPerson over Person", but I don't think, that C# has such a feature.

  1. Way - imho the best and cleanest way - use reflection

I often use a method, which just copies all field's to an inheriting target object.

I'm sure there are way more pattern's to implement this, but most of them will just copy all of the data, which is slow and messy. Are'nt there any better way's?

Aucun commentaire:

Enregistrer un commentaire