Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making Extension Methods/Constructors of a wrapper class Generic

In a service (that I cannot alter) I have two object classes Bar and Baz with mostly similar properties (but sadly NO, they don't derive from the same base class or inherit from the same Interface... yeah -- dumb), as well as a dependency class related to their relative BarQux and BazQux properties:

public class Bar                          public class Baz
{                                         {
    public int ID { get; set; }               public int ID { get; set; }
    public bool Active { get; set; }          public bool Active { get; set; }
    public int BarQux { get; set; }           public int BazQux { get; set; }
    ...                                       ...
}                                         }

public class Qux
{
    public int ID { get; set; } // Corresponds to BarQux and BazQux
    public string Name { get; set; }
}

In a WPF screen, I am binding a list of each type (Baz and Bar) to two seperate ListViews. I need each to have an additional Selected CheckBox column. To do so, I've created a wrapper class with the common properties, the additional Selected property, and a constructor for each:

public class Foo
{
    public Foo(Bar bar, Qux qux)
    {
        this.Active = bar.Active;
        this.FooQux = string.Format("{0} - {1}", qux.ID, qux.Name);
        ...
    }

    public Foo(Baz baz, Qux qux)
    {
        this.Active = baz.Active;
        this.FooQux = string.Format("{0} - {1}", qux.ID, qux.Name);
        ...
    }

    public bool Selected { get; set; }
    public int ID { get; set; }
    public bool Active { get; set; }
    public string FooQux { get; set; }
    ...
}

To convert each collection of class Baz and Bar to collections of Foo, I created the following extension methods:

public static List<Foo> ToFoo(this IEnumerable<Bar> bars, IEnumerable<Qux> quxs)
{
    List<Foo> foos = new List<Foo>();

    foreach (Bar bar in bars)
    {
        Foo foo = new Foo(bar, quxs.Single(qux => qux.ID == bar.BarQux));
        foos.Add(foo);
    }

    return foos;
}

public static List<Foo> ToFoo(this IEnumerable<Baz> bazs, IEnumerable<Qux> quxs)
{
    List<Foo> foos = new List<Foo>();

    foreach (Baz baz in bazs)
    {
        Foo foo = new Foo(baz, quxs.Single(qux => qux.ID == baz.BazQux));
        foos.Add(foo);
    }

    return foos;
}

Question:

How do I make this generic?

Theory, Implementation, and Error:

  1. Since the constructors are virtually the same besides the Bar and Baz parameters, can I somehow use generic type T to make one constructor and still grab the properties?

    public class Foo<T>
    {
        public Foo(T obj, Qux qux)
        {
            this.Active = obj.Active; // 'T' does not contain a definition for 'Active'...
            this.Qux = string.Format("{0} - {1}", qux.ID, qux.Name);
            ...
        }
        ...
    }
    
  2. Change the constructors to receive the whole collection of Qux objects and do the quxs.Single(qux => qux.ID == object.ObjectQux) logic there. Then make the extension methods into one generic method, something like the following.

    public static List<Foo> ToFoo<T>(this IEnumerable<T> objCollection, IEnumerable<Qux> quxs)
    {
        List<Foo> foos = new List<Foo>();
    
        foreach (T obj in objCollection)
        {
            Foo foo = new Foo(obj, quxs); // The best overloaded method... has some invalid arguments.
            foos.Add(foo);
        }
    
        return foos;
    }
    
  3. Both 1 and 2 combined? Anything I haven't thought of?

like image 721
OhBeWise Avatar asked Dec 28 '25 02:12

OhBeWise


1 Answers

If you have limited properties and the number of items in the list is also few then you can use Reflection. Since you will use this in WPF I would also suggest that the process be moved to a separate background thread.

Generic Foo

public class Foo<T>
{
    public Foo(T obj, Qux qux)
    {
        //this.Active = obj.Active;

        var fooProps = GetType().GetProperties().ToList();
        var tProps = typeof(T).GetProperties()
            .Where(p =>
            {
                var w = fooProps.FirstOrDefault(f => f.Name == p.Name);
                return w != null;
            }).ToList();

        foreach (var propertyInfo in tProps)
        {
            var val = propertyInfo.GetValue(obj);
            fooProps.First(e => e.Name == propertyInfo.Name).SetValue(this, val);
        }
        this.FooQux = string.Format("{0} - {1}", qux.ID, qux.Name);
    }
    public bool Selected { get; set; }
    public int ID { get; set; }
    public bool Active { get; set; }
    public string FooQux { get; set; }
}

Your extension methods

    public static IEnumerable<Foo<Bar>> ToFoo(this IEnumerable<Bar> bars, IEnumerable<Qux> quxs)
    {
        return bars.
            Select(bar => new Foo<Bar>(bar, quxs.Single(qux => qux.ID == bar.BarQux))).ToList();
    }

    public static IEnumerable<Foo<Baz>> ToFoo(this IEnumerable<Baz> bazs, IEnumerable<Qux> quxs)
    {
        return bazs.
            Select(baz => new Foo<Baz>(baz, quxs.Single(qux => qux.ID == baz.BazQux))).ToList();
    }
    public static IEnumerable<Qux> ToQuxes(this IEnumerable<BazQux> bazQuxs)
    {
        return bazQuxs.Select(b => new Qux(typeof(BazQux), b)).ToList();
    }

    public static IEnumerable<Qux> ToQuxes(this IEnumerable<BarQux> barQuxes )
    {
        return barQuxes.Select(b => new Qux(typeof(BarQux), b)).ToList();
    }

Similarly you can also convert your BarQux or BazQux into the non generic Qux class.

public class Qux
{
    public int ID { get; set; } // Corresponds to BarQux and BazQux
    public string Name { get; set; }

    public Qux(Type type, object obj)
    {
        var ob = Convert.ChangeType(obj, type);

        var quxProps = GetType().GetProperties();
        var obProps = ob.GetType().GetProperties()
            .Where(p =>
            {
                var w = quxProps.FirstOrDefault(f => f.Name == p.Name);
                return w != null;
            }).ToList();
        foreach (var propertyInfo in obProps)
        {
            var val = propertyInfo.GetValue(obj);
            quxProps.First(e => e.Name == propertyInfo.Name).SetValue(this, val);
        }

    }
}

You can then just call ToFoo extension method and voila you have a list of Foo.

You can also convert Foo to non-generic by using the logic of Qux class

like image 184
Sandesh Avatar answered Dec 30 '25 17:12

Sandesh



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!