开发者

constructor chaining

Sample code :

public class CA
{
    public C开发者_如何转开发A(string s, List<int> numList)
    {
        // do some initialization
    }

    public CA(string s, int num) : this(s, ListHelper.CreateList(num))
    {
    }
}

public static class ListHelper
{
    public static List<int> CreateList(int num)
    {
        List<int> numList = new List<int>();
        numList.Add(num);
        return numList;
    }
}

The second constructor in "CA" uses constructor chaining. Inside the "this" call, I want to convert an int into a List with one member. The code works via the helper function "CreateList", but I'm wondering if there is a cleaner way than this. i.e. is there some way to do it without the helper method.

To date, in situations like this, I probably wouldn't bother using constructor chaining. Thoughts ?


Try:

public CA(string s, int num) : this(s, new List<int>(new int[] { num }))
{
}

This should match the constructor overload which takes an IEnumerable<T> (which an array of T[] is convertible to).


I would ditch the ListHelper in favor of the following:

public CA(string s, int num) : this(s, new List<int>(){num}){}


I have a little something in my extensions for when I don't have an enumerable of something to initiate a list, that should do the trick.

namespace Linq1
{
    class Program
    {
        static void Main(string[] args)
        {
            int value = 10;
            List<int> list = value.ToList();
        }
    }

    public static class Extensions
    {
        public static List<T> ToList<T>(this T lonely) where T : struct
        {
            return new List<T>(new T[] { lonely });
        }
    }
}

and used in your code:

public class CA
{
    public CA(string s, List<int> numList)
    {
        // do some initialization
    }

    public CA(string s, int num) : this(s, num.ToList())
    {
    }
}


Looking at your code, I'm presuming you want to use the first CA constructor to do the initialization, and the second CA constructor (string, int) needs no initialization of its own -- it just passes control to the first.

First, the rule of thumb for constructor chaining is to accomplish the primary purpose of chaining - to eliminate duplicate or overly-complex initialization code (i.e. the lowest level in the chain is the only constructor that contains any real initialization code). Your example is already doing this, which is good.

Second, if you're using .NET 4, you can use optional arguments on the constructor to get rid of unnecessary, additional constructors, thus eliminating the need for chaining. So you could implement CA this way instead:

    public class CA
    {
        public CA(string s, List<int> numList = null, int num = 0)
        {
            // do some initialization
            if (numList == null)
            {
                numList = new List<int>();
                numList.Add(num);
            }
        }
    }

Now you have only one constructor, so chaining is unnecessary. Also unnecessary is your helper function and the static class to house it. Client code using the above definition would be something like:

        int iMyInt = 1;
        List<int> myIntList = new List<int>();
        myIntList.Add(iMyInt);
        CA caListMethod = new CA("ListMethod", myIntList);
        CA caIntMethod = new CA("IntMethod", null, iMyInt);

If you don't like the 'caIntMethod' call above for some reason, you can use another new feature of .NET 4, dynamic types, which can make the client code even cleaner. Your CA class could look something like this instead:

    public class CA
    {
        public CA(string s, dynamic InitValue)
        {
            List<int> InitList = null;
            if (InitValue is List<int>)
                InitList = InitValue;
            else if (InitValue is int)
            {
                InitList = new List<int>();
                InitList.Add(InitValue);
            }

            // Now, InitList contains your list for further initialization,
            //  if the client passed either a List<int> or an int:
            if (InitList != null)
            {
                // do some initialization
            }
        }
    }

And the new client code would look something like this:

        int iMyInt = 1;
        List<int> myIntList = new List<int>();
        myIntList.Add(iMyInt);
        CA caListMethod = new CA("ListMethod", myIntList);
        CA caIntMethod = new CA("IntMethod", iMyInt);

You will notice the only difference in this client code from the previous example is that now you only have a single constructor that takes two arguments, and the second argument has a dynamic type. So you could enhance your constructor in the future to process many other types of init values, with no impact on the client.

The caveat to my second example is that the dynamic type automatically performs type coercion at runtime, which is a bit of processing overhead. However, if you want to use some sort of "generic" constructor to allow for the polymorphic nature of a generic reference (hence, the extensibility I mentioned), you're going to get into type checking and coercion in your own code anyway. The beauty of dynamic is that instead of handling such stuff in your own code, the .NET 4 runtime does it for you. So in terms of performance, it's usually a wash.

If you really need a generic, extensible type, using a dynamic type makes for cleaner code, both for the client and for the class.

Hope this helps,

Mark

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜