locked
How to cast from a type variable RRS feed

  • Question

  • I don't really know how to explain this but I can show it then explain it, if that makes sense.

    private Type[] types = { typeof(byte), typeof(decimal), typeof(double), typeof(float), typeof(int), typeof(long) };
            private string[] formats = { "0", "0.0000000000000000000000000000", "0.000000000000000", "0.000000", "0" };
    
    protected override void OnLoad(EventArgs e)
            {
                this.comboBox1.SelectedIndex = 3;
                int seletedIndex = this.comboBox1.SelectedIndex;
                Type type = types[seletedIndex];
                FieldInfo maxValue = type.GetField("MaxValue");
                
                this.textBox1.Text = "Max Value is: " +
                    ((type)maxValue.GetValue(null)).ToString(this.formats[seletedIndex]) +
                    "\nMin Value is: " +
                    ((type)type.GetField("MinValue").GetValue(null)).ToString(this.formats[seletedIndex]);
            }

    The error is where it does the casts ((type)maxvalue and ((type).type.GetField

    What I want is it to have the correct cast for each type when it's getting the max value.  The current state it's at is set to float, so if I were to replace the type with float the code would work just ask I would like it.

    I know I probably didn't explain that good at all for anyone to contemplate.  Hopefully someone will understand, and hopefully what i'm trying to do is possible.

    Monday, April 15, 2013 6:23 AM

Answers

  • You can't cast to a type that's known only at runtime, the type you want to cast has to be known at compile time. What you can do in this particular case is to use the IFormattable interface that all number types implement and allows you to call a ToString overload that takes a format parameter:

    Type type = types[seletedIndex];
    
    IFormattable maxValue = (IFormattable)type.GetField("MaxValue").GetValue(null);
    IFormattable minValue = (IFormattable)type.GetField("MinValue").GetValue(null);
    string format = formats[seletedIndex];
    IFormatProvider formatProvider = System.Globalization.CultureInfo.CurrentCulture;
    
    this.textBox1.Text = "Max Value is: " + maxValue.ToString(format, formatProvider)
                   + "\r\nMin Value is: " + minValue.ToString(format, formatProvider);
    

    An alternative would be to call the ToString overload you want using reflection but I think using IFormattable is more appropiate, reflection should only be used only when there's no other way.

    Yet another alternative would be to use String.Format and create the format string at runtime. This way you don't need any casting:

    object maxValue = type.GetField("MaxValue").GetValue(null);
    object minValue = type.GetField("MinValue").GetValue(null);
    string format = formats[seletedIndex];
    
    this.textBox1.Text = String.Format("Max Value is: {0:" + format + "} \r\nMin Value is: {1:" + format + "}", maxValue, minValue);
    
    Works well in this case but I wouldn't recommend creating format strings at runtime like this, it's less readable and there may be security implications if the format string can contain user input.
    • Marked as answer by Bob Shen Friday, May 3, 2013 5:29 AM
    Monday, April 15, 2013 7:17 AM
  • If your ComboBox's items are added using the object instances themselves as opposed to just the string representation, you can cast using the Convert class.

    From my interpretation of your post, here is a snippet I wrote:

    public NewType CastSelectedItemTo<NewType>()
    {
        object selected = comboBox1.SelectedItem;
        NewType castResult = default(NewType);
    
        try // Try the conversion
        {
            castResult = (NewType)Convert.ChangeType(selected, typeof(NewType));
        }
        catch (Exception ex) // The conversion failed :(
        {
            Console.WriteLine(ex.StackTrace);	
        }
    
        return castResult;
    }
    

    Is this what you were looking for?

    • Proposed as answer by Impulser Monday, April 15, 2013 7:18 AM
    • Marked as answer by Bob Shen Friday, May 3, 2013 5:29 AM
    Monday, April 15, 2013 7:17 AM
  • Well this is tricky.

    Type itself does not have a MaxValue Property and that is the reason you recieve the error.

    In order for it to work, You must cast the type variable into a relevent type.

    A Quick and Dirty solution would be to try to cast the variable to all the types int the types array from the larger type to the smallest wrapping each with a try catch.

    However, in such a case, c# might allow you to upcast all the types without an exception so you really need to check this solution befor implementing it.

    • Marked as answer by Bob Shen Friday, May 3, 2013 5:29 AM
    Monday, April 15, 2013 7:26 AM
  • I see two big flaws in this code:

    1. You catch exception. DON'T catch exception. Or at least only once per Thread.

    2. You only expose the StackTrace. Wich is better then just the message, but still not the way to go. Always use ex.ToString(), because that gives Stacktrace, the Message and the InnerException(plus it's stacktrace).

    See here about proper ExceptionHandling:

    http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET


    Let's talk about MVVM: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/b1a8bf14-4acd-4d77-9df8-bdb95b02dbe2

    • Marked as answer by Bob Shen Friday, May 3, 2013 5:29 AM
    Monday, April 15, 2013 9:41 AM
  • Cast is not the way to solve your problem. Instead, I would use "dynamic" to get at the ToString(String) method for formatting:

    protected override void OnLoad(EventArgs e)
    {
        this.comboBox1.SelectedIndex = 3;
        int seletedIndex = this.comboBox1.SelectedIndex;
        Type type = types[seletedIndex];
        dynamic maxValue = type.GetField("MaxValue").GetValue(null);
        dynamic minValue = type.GetField("MinValue").GetValue(null);
        string maxValueFormatted = maxValue.ToString(this.formats[seletedIndex]);
        string minValueFormatted = minValue.ToString(this.formats[seletedIndex]);
    
        this.textBox1.Text = string.Format("Max Value is: {0}\nMin Value is: {1}",
                                           maxValueFormatted, minValueFormatted);
    }

    Marcus Björklund

    Please use "Mark As Answer" if my post has answered your question, and/or vote for it if you find it helpful. Thanks!

    • Marked as answer by Bob Shen Friday, May 3, 2013 5:29 AM
    Monday, April 15, 2013 10:11 AM

All replies

  • You can't cast to a type that's known only at runtime, the type you want to cast has to be known at compile time. What you can do in this particular case is to use the IFormattable interface that all number types implement and allows you to call a ToString overload that takes a format parameter:

    Type type = types[seletedIndex];
    
    IFormattable maxValue = (IFormattable)type.GetField("MaxValue").GetValue(null);
    IFormattable minValue = (IFormattable)type.GetField("MinValue").GetValue(null);
    string format = formats[seletedIndex];
    IFormatProvider formatProvider = System.Globalization.CultureInfo.CurrentCulture;
    
    this.textBox1.Text = "Max Value is: " + maxValue.ToString(format, formatProvider)
                   + "\r\nMin Value is: " + minValue.ToString(format, formatProvider);
    

    An alternative would be to call the ToString overload you want using reflection but I think using IFormattable is more appropiate, reflection should only be used only when there's no other way.

    Yet another alternative would be to use String.Format and create the format string at runtime. This way you don't need any casting:

    object maxValue = type.GetField("MaxValue").GetValue(null);
    object minValue = type.GetField("MinValue").GetValue(null);
    string format = formats[seletedIndex];
    
    this.textBox1.Text = String.Format("Max Value is: {0:" + format + "} \r\nMin Value is: {1:" + format + "}", maxValue, minValue);
    
    Works well in this case but I wouldn't recommend creating format strings at runtime like this, it's less readable and there may be security implications if the format string can contain user input.
    • Marked as answer by Bob Shen Friday, May 3, 2013 5:29 AM
    Monday, April 15, 2013 7:17 AM
  • If your ComboBox's items are added using the object instances themselves as opposed to just the string representation, you can cast using the Convert class.

    From my interpretation of your post, here is a snippet I wrote:

    public NewType CastSelectedItemTo<NewType>()
    {
        object selected = comboBox1.SelectedItem;
        NewType castResult = default(NewType);
    
        try // Try the conversion
        {
            castResult = (NewType)Convert.ChangeType(selected, typeof(NewType));
        }
        catch (Exception ex) // The conversion failed :(
        {
            Console.WriteLine(ex.StackTrace);	
        }
    
        return castResult;
    }
    

    Is this what you were looking for?

    • Proposed as answer by Impulser Monday, April 15, 2013 7:18 AM
    • Marked as answer by Bob Shen Friday, May 3, 2013 5:29 AM
    Monday, April 15, 2013 7:17 AM
  • Well this is tricky.

    Type itself does not have a MaxValue Property and that is the reason you recieve the error.

    In order for it to work, You must cast the type variable into a relevent type.

    A Quick and Dirty solution would be to try to cast the variable to all the types int the types array from the larger type to the smallest wrapping each with a try catch.

    However, in such a case, c# might allow you to upcast all the types without an exception so you really need to check this solution befor implementing it.

    • Marked as answer by Bob Shen Friday, May 3, 2013 5:29 AM
    Monday, April 15, 2013 7:26 AM
  • I see two big flaws in this code:

    1. You catch exception. DON'T catch exception. Or at least only once per Thread.

    2. You only expose the StackTrace. Wich is better then just the message, but still not the way to go. Always use ex.ToString(), because that gives Stacktrace, the Message and the InnerException(plus it's stacktrace).

    See here about proper ExceptionHandling:

    http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET


    Let's talk about MVVM: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/b1a8bf14-4acd-4d77-9df8-bdb95b02dbe2

    • Marked as answer by Bob Shen Friday, May 3, 2013 5:29 AM
    Monday, April 15, 2013 9:41 AM
  • Cast is not the way to solve your problem. Instead, I would use "dynamic" to get at the ToString(String) method for formatting:

    protected override void OnLoad(EventArgs e)
    {
        this.comboBox1.SelectedIndex = 3;
        int seletedIndex = this.comboBox1.SelectedIndex;
        Type type = types[seletedIndex];
        dynamic maxValue = type.GetField("MaxValue").GetValue(null);
        dynamic minValue = type.GetField("MinValue").GetValue(null);
        string maxValueFormatted = maxValue.ToString(this.formats[seletedIndex]);
        string minValueFormatted = minValue.ToString(this.formats[seletedIndex]);
    
        this.textBox1.Text = string.Format("Max Value is: {0}\nMin Value is: {1}",
                                           maxValueFormatted, minValueFormatted);
    }

    Marcus Björklund

    Please use "Mark As Answer" if my post has answered your question, and/or vote for it if you find it helpful. Thanks!

    • Marked as answer by Bob Shen Friday, May 3, 2013 5:29 AM
    Monday, April 15, 2013 10:11 AM