tags:

views:

144

answers:

5

I've got a generic class:

public class BaseFieldValue<T>
{
    public BaseFieldValue()
    {
        //...
    }

    public BaseFieldValue(string value)
    {
        //...
    }

    public BaseFieldValue(T value)
    {
        //...
    }
}

Fine. Except...

var myValue = new BaseFieldValue<string>("hello");

Oops. The undesired constructor is called. There's a number of ways to address the problem. What's the best solution?

+7  A: 

I would probably make one of the overloads into a factory method:

public static BaseFieldValue<T> Parse(string value){}
Joshua Flanagan
What if BaseFieldValue is a Database connection class and the string is the connection string?
Yuriy Faktorovich
@Yuriy this would still be viable in that case.
Rex M
@Rex, yes, but it would work unlike other Database connection classes, just trying to preserve patterns.
Yuriy Faktorovich
I tested an implementation of this with our development team and they found it very intuitive. Cheers!
Rex M
+2  A: 

You could do the following:

public class BaseFieldValue<T>
{
    public struct Special
    {
        internal string m_value;
        public Special(string value)
        {
            m_value = value;
        }
    }

    public BaseFieldValue()
    {
        //...
    }

    public BaseFieldValue(Special value)
    {
        //...
    }

    public BaseFieldValue(T value)
    {
        //...
    }
}

... or, you could add an extra ignored boolean parameter to your special constructor, just to disambiguate it.

ChrisW
+1 for your last option
recursive
A: 

A nasty hack, but probably no worse than any of the alternatives:

public class BaseFieldValue<T>
{
    public BaseFieldValue()
    {
        // ...
    }

    public BaseFieldValue(StringWrapper value)
    {
        // ...
    }

    public BaseFieldValue(T value)
    {
        // ...
    }

    public class StringWrapper
    {
        private string _value;

        public static implicit operator string(StringWrapper sw)
        {
            return sw._value;
        }

        public static implicit operator StringWrapper(string s)
        {
            return new StringWrapper { _value = s };
        }
    }
}

And now it can be used as you need:

// call the generic constructor
var myValue = new BaseFieldValue<string>("hello");

// call the string constructor
var myValue = new BaseFieldValue<int>("hello");
LukeH
+1  A: 

Couldn't make Type Contraints do what I wanted, so my workaround is removing the ambiguous constructor while retaining the special case for string:

public class BaseFieldValue<T>
{
    public BaseFieldValue()
    {
        //...
    } 

    public BaseFieldValue(T value) 
    {
        //however many things you need to test for here
        if (typeof(T) == typeof(string))
        {
            SpecialBaseFieldValue(value.ToString());
        }
        else
        {
            //everything else
        }
        //...
    }

    private void SpecialBaseFieldValue(string value)
    {
        //...
    }

}
rick schott
But `typeof(T)` will *never* equal `typeof(string)` when you're using an instance of `BaseFieldValue<int>`, `BaseFieldValue<DateTime>`, `BaseFieldValue<CustomType>` etc.
LukeH
My unit test for string and int worked fine.
rick schott
A: 

May be you can try thi:

var myValue = new BaseFieldValue<Object>("hello" as Object);
Amit
@Amy that would seem to defeat the purpose of having a generic class.
Rex M