5

We created Id32 and Id64 struct to wrap integers and long values coming from DB, so they can be explicitly processed as IDs by a Json converter (with dedicated custom converters).

The problem is that we read this data from a Dictionary<string, object> that actually is a DataRow-like object where the string part is the name of the column and the object part is the value.

So before we had this code to read the value:

int myVal = (int)row["COLUMN"]

We want this code to continue working also after these changes.

But since row["COLUMN"] is an object (@ compile-time) the implicit cast fails, even though it is actually an Id32 (@ run-time).

The following obviously works:

int myVal = (Id32)row["COLUMN"]

But is there some to way to fix this without modifying the code that reads the value?

This is the struct code:

public struct Id32
{
    public readonly int Value;

    public Id32(int id) { this.Value = id; }

    public static implicit operator int(Id32 id) { return id.Value; }

    public static implicit operator Id32(int id) { return new Id32(id); }
}
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
Teejay
  • 7,210
  • 10
  • 45
  • 76
  • See also: http://stackoverflow.com/questions/1611083/will-the-c-sharp-compiler-perform-multiple-implicit-conversions-to-get-from-one – Binkan Salaryman Jul 07 '15 at 11:30
  • This question is about implicit conversions, not casts. Though casting is involved (you have an `object` and it needs to be cast to `int`, possibly inside of an implicit conversion from `object` defined on `Id32`). – binki Dec 05 '17 at 22:33

2 Answers2

3

I think this is not possible with the constraint not to modify your retrieving code int myVal = (int)row["COLUMN"].

You would need to add an implicit cast to object (to int) which cannot be done. There are many ways to make your own cast simple but everyone I can think of or you will find like here requires to change that line.

Even if you not change it I guess you will have to recompile it - so if you recompile it, why not change it? There are some refactoring tools which should make even thousands of that lines quite easy.

Community
  • 1
  • 1
ZoolWay
  • 5,411
  • 6
  • 42
  • 76
2

In my opinion not a very decent solution, but it works (hope there are better solutions): if you use dynamic the underlying type is determined on run-time, so the type check with the implicit cast will work.

The code I have used:

dynamic o = new Id32(1);
// dynamic o = row["COLUMN"]; in your case

int myVal = (int)o;

If you change dynamic to object you will have your current situation, which fails.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • 1
    This is interesting indeed. But I don't really know if it's possible to declare a `Dictionary`... I'll give it a try. – Teejay Jul 07 '15 at 11:22
  • No, but it is converted at that time already (if you do this before adding to the dictionary), so it doesn't matter. – Patrick Hofman Jul 07 '15 at 11:23
  • Unfortunately, that way, we need to modify the code to read the value anyway. – Teejay Jul 07 '15 at 11:24
  • 1
    Well that works surprisingly, but as you stated - this is a dirty solution. (``var row = new Dictionary { {"COLUMN", new Id32(42)} };``) – Binkan Salaryman Jul 07 '15 at 11:28
  • Okay, my bad. A dictionary with `Value` type `dynamic` will work too. – Patrick Hofman Jul 07 '15 at 11:28
  • `dynamic` does not exist in the CLR type system. If the C# code doing the cast is expecting an `object` nothing dynamic will happen. You need to modify it so that it considers the dictionary to have dynamic values. – usr Jul 07 '15 at 11:29