Implicit Operators and Assignments to SqlParameter.Value with IConvertible Error

459 views Asked by At

I have a class member type as Int32 but the requirement is that the .ToString() method of this member needs to return a special formatted version of the Int32. So I created a struct with implicit operators which preserves the simple value assignment semantics and I can override .ToString()...

public struct MyValue
{
    private int _val;

    public MyValue(int val) { _val = val; }

    public static implicit operator int(MyValue value)
    {
        return value._val;
    }

    public static implicit operator MyValue(int value)
    {
        return new MyValue(value);
    }

    public override string ToString()
    {
        return _val.ToString("0000000000");
    }
}

In typical usage it functions as expected. However, when I assign to the SqlParameter.Value member I end up getting a "...use IConvertible..." error...

string connString = "Server=svr;Database=db;Trusted Connection=Yes";
string sql = "SELECT * FROM [tbl] WHERE [val] = @val";

MyValue val = 256;

SqlParameter parm = new SqlParameter("@val", SqlDbType.Int);
parm.Value = val;

using ( SqlConnection conn = new SqlConnection(connString) )
{
    conn.Open();
    using ( SqlCommand cmd = new SqlCommand(sql, conn) )
    {
        cmd.Parameters.Add(parm);
        using ( SqlDataReader rdr = cmd.ExecuteReader() )
        {
            while ( !rdr.Read() ) { }
            rdr.Close();
        }
    }
    conn.Close();
}

While debugging, it looks like the .ToString() method on my struct gets called on the SqlParameter.Value assignment. So question #1 is why is it doing that instead of assigning the underlying Int32 value?

Related question #2 is why does the initial assignment not generate the error, as the error is generated in the SqlCommand.ExecuteReader() method?

Feel free to critique any aspect of the code I've written, but I'm really hoping to get good answers to my questions.

(edited to add) I will re-phrase my issue...

I need to create a value data type that exactly mimics Int32 (with the .ToString() excpetion), so that when it gets boxed, the Int32 value is boxed instead of the struct.

Is this possible?

1

There are 1 answers

2
jam40jeff On

SqlParameter.Value is typed object, so the compiler does not know to call the implicit operator to convert the MyValue instance val to an int.

Something like the following should work, however:

static SqlParameter GetIntSqlParameter(string name, int value)
{
    SqlParameter parm = new SqlParameter(name, SqlDbType.Int);
    parm.Value = value;
    return parm;
}

which can be called as:

SqlParameter parm = GetIntSqlParameter("@val", val);

or as Jeppe pointed out in the comments, casting to int works as well (but then the operator may as well be defined as explicit.

I was too busy typing a mini-rant about how this is why I hate implicit conversions.