2

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?

  • Instead of `"0000000000"` you can also use `"D10"`. – Jeppe Stig Nielsen Jan 04 '13 at 23:28
  • because you are assigning Struct to an object....make the struct to class – Dan Hunex Jan 04 '13 at 23:31
  • @DanHunex No, I don't think it would help. – Jeppe Stig Nielsen Jan 04 '13 at 23:39
  • Who knows what home-made types the code in `System.Data.SqlClient` can handle? According to the error message, it might work if your struct implemented the `IConverible` interface. `Int32` implements that, so you could redirect every call to the explicit interface implementation of `Int32`. But it's a whole lot of ugly code. As I said elsewhere, why not just say `parm.Value = (int)val;` in cases like this? – Jeppe Stig Nielsen Jan 04 '13 at 23:50
  • And to add this is a design issue at this point in time. – Chris Gallucci Jan 05 '13 at 02:20
  • 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? – Chris Gallucci Jan 07 '13 at 17:53

1 Answers1

0

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.

jam40jeff
  • 2,576
  • 16
  • 14
  • 1
    Exactly! So instead of saying `parm.Value = val;`, he should say `parm.Value = (int)val;` because we know everything can handle `int` (also `Int32` does implement `IConvertible`). – Jeppe Stig Nielsen Jan 04 '13 at 23:33
  • Yes, both the casting and implementing IConvertible both work. Our requirements disallow the casting and I'm trying to find a way from having to implement IConvertible, just because of all the excess "noise". – Chris Gallucci Jan 05 '13 at 02:12