Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor or Explicit cast

In working with Linq to Sql I create a seperate class to ferry data to a web page. To simplify creating these ferry objects I either use a specialized constructor or an explicit conversion operator. I have two questions.

First which approach is better from a readibility perspective?

Second while the clr code that is generated appeared to be the same to me, are there situations where one would be treated different than the other by the compiler (in lambda's or such).

Example code (DatabaseFoo uses specialized constructor and BusinessFoo uses explicit operator):

public class DatabaseFoo
{
    private static int idCounter; // just to help with generating data
    public int Id { get; set; }
    public string Name { get; set; }

    public DatabaseFoo()
    {
        Id = idCounter++;
        Name = string.Format("Test{0}", Id);
    }
    public DatabaseFoo(BusinessFoo foo)
    {
        this.Id = foo.Id;
        this.Name = foo.Name;
    }
}

public class BusinessFoo
{
    public int Id { get; set; }
    public string Name { get; set; }

    public static explicit operator BusinessFoo(DatabaseFoo foo)
    {
        return FromDatabaseFoo(foo);
    }


    public static BusinessFoo FromDatabaseFoo(DatabaseFoo foo)
    {
        return new BusinessFoo {Id = foo.Id, Name = foo.Name};
    }
}

public class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Creating the initial list of DatabaseFoo");
        IEnumerable<DatabaseFoo> dafoos = new List<DatabaseFoo>() { new DatabaseFoo(), new DatabaseFoo(), new DatabaseFoo(), new DatabaseFoo(), new DatabaseFoo(), new DatabaseFoo()};

        foreach(DatabaseFoo dafoo in dafoos)
            Console.WriteLine(string.Format("{0}\t{1}", dafoo.Id, dafoo.Name));

        Console.WriteLine("Casting the list of DatabaseFoo to a list of BusinessFoo");
        IEnumerable<BusinessFoo> bufoos = from x in dafoos
                                          select (BusinessFoo) x;

        foreach (BusinessFoo bufoo in bufoos)
            Console.WriteLine(string.Format("{0}\t{1}", bufoo.Id, bufoo.Name));

        Console.WriteLine("Creating a new list of DatabaseFoo by calling the constructor taking BusinessFoo");
        IEnumerable<DatabaseFoo> fufoos = from x in bufoos
                                         select new DatabaseFoo(x);

        foreach(DatabaseFoo fufoo in fufoos)
            Console.WriteLine(string.Format("{0}\t{1}", fufoo.Id, fufoo.Name));
    }
}
like image 771
Felan Avatar asked Feb 27 '23 05:02

Felan


1 Answers

I'm not a big fan of conversions for the most part - whether explicit or implicit. The same syntax: (TypeName) expression is used for various different kinds of conversion, and it can get a bit confusing to know which type the compiler is applying.

A static factory method like FromDatabaseFoo is good - and you might also want to have an instance method of ToBusinessFoo on DatabaseFoo. Both of these are clearer than user-defined conversions in my view.

(That's not to say that custom conversions are always a bad idea, mind you. I'm just wary of them in general.)

like image 70
Jon Skeet Avatar answered Mar 11 '23 22:03

Jon Skeet