1

I have a method that returns a type of object based on the given column (a database class). However, when I assign the object the compiler throws an error saying it cannot implicitly convert type of object to int. How can I convert it without casting?

It looks better as:

this.Id = datum["Id"];

But now I have to include a cast, which makes the code a bit less clean and harder to code:

this.Id = (int)datum["Id"];

Here's my code:

public object this[string name]
    {
        get
        {
            object result;

            if (this.Dictionary.ContainsKey(name))
            {
                if (this.Dictionary[name] is DBNull)
                {
                    result = null;
                }
                else if (this.Dictionary[name] is byte && Meta.IsBool(this.Table, name))
                {
                    result = (byte)this.Dictionary[name] > 0;
                }
                else
                {
                    result = this.Dictionary[name];
                }
            }
            else
            {
                result = default(object);
            }

            return result;
        }
        set
        {
            if (value is DateTime)
            {
                if (Meta.IsDate(this.Table, name))
                {
                    value = ((DateTime)value).ToString("yyyy-MM-dd");
                }
                else if (Meta.IsDateTime(this.Table, name))
                {
                    value = ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
                }
            }

            if (this.Dictionary.ContainsKey(name))
            {
                this.Dictionary[name] = value;
            }
            else
            {
                this.Dictionary.Add(name, value);
            }
        }
    }

4 Answers 4

3

You could change your indexer signature to:

public dynamic this[string name]

That would then make the conversion dynamic at execution time.

Personally, I prefer the cast approach though. It makes it clear that this is something that can fail - that you're telling the compiler that you have information which isn't available to it.

As an aside, your code can be written rather more simply, taking advantage of Dictionary<,>.TryGetValue and the behaviour of the dictionary indexer for setting:

public object this[string name]
{
    get
    {
        object result;
        if (Dictionary.TryGetValue(name, out result))
        {
            if (result is DBNull)
            {
                result = null;
            }
            else if (result is byte && Meta.IsBool(this.Table, name))
            {
                result = (byte) result > 0;
            }
        }
        return result;
    }
    set
    {
        // TODO: Byte/bool conversions?

        if (value is DateTime)
        {
            // Note use of invariant culture here. You almost certainly
            // want this, given the format you're using. Preferably,
            // avoid the string conversions entirely, but...
            DateTime dateTime = (DateTime) value;
            if (Meta.IsDate(this.Table, name))
            {
                value = dateTime.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
            }
            else if (Meta.IsDateTime(this.Table, name))
            {
                value = dateTime.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
            }
        }

        Dictionary[name] = value;
    }
}
Sign up to request clarification or add additional context in comments.

8 Comments

I've used the dynamic approach before. However, after a few tests I figured out it's really slow and slows down my program by a lot of time. So, I changed this approach.
+1 for answering the question AND politely suggesting with a voice of expertise that fewer characters is not always better.
@JonSkeet If I use dynamic /only/ when returning the objects by a given column, would it slow down my application? My approach before that was making the class that holds the dictionary a DynamicObject, however, I changed that because it was too slow. If I do use dynamic but only when returning the object, would it also be slow as before?
@GilbertWilliams: There's an easy way to tell, isn't there? I'd be surprised if this were actually a bottleneck - but as I say, I'd personally stick with the cast.
@GillsoftAB: The conversion itself has to be done at execution-time either way. I'd be surprised to see a situation where performance would be the governing factor here. Desired behaviour in various situations and readability are far more important, IMO.
|
1

Use class Convert:

Convert.ToInt32(datum["Id"]);

1 Comment

I know how to convert, but it still looks less clean. Is there a way to make the method somehow return the type that is needed? The dictionary is a collection of <string, object>. The string is the column of the table and the object is the value.
0

If you didn't need to state in your code that you are casting from object to int, then the programming language would not be helping you avoid mistakes.

C# does have a feature where you can switch off static type checking for specific variables: make your indexer return dynamic:

public dynamic this[string name]

Then you'll be able to say:

int n = datum["Id"];

But the downside is that you won't find out if this is correct until runtime.

Comments

0

You can do an extension method.

Create a class like this.

public static class ExtensionMethods
{
    public static int AsInt(this object obj)
    {
        return (int)obj; // add additional code checks here
    }
}

Then in your actual code all you have to do is call the extension method like this.

this.Id = datum["Id"].AsInt();

I know this may look the same as the cast but it happens underneath the method call AsInt and your code is cleaner and easier to read since AsInt is fluent and definitive.

2 Comments

@GilbertWilliams Thanks, if you're satisfied with the answer, please do upvote and mark as answer so this question can be closed.
Following normal .NET naming conventions, it would be better as AsInt32 or ToInt32.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.