简体   繁体   中英

C#: How can I use implicit cast operator during object to type conversion?

HI!

Here is my case: I have some value type which is wrapped into another type with appropriate implicit converters. If I cast wrapped type to an object and then try to get original value I can do that in two-step cast only. If simplified my code is as follows:

public enum MyEnum : int
    {
        First,
        Second
    }


    public class Test<T>
    {
        public Test(T val)
        {
            Value = val;
        }

        private T Value { get; set; }


        public static implicit operator T(Test<T> m)
        {
            return m.Value;
        }

        public static implicit operator Test<T>(T m)
        {
            var res = new Test<T>(m);
            return res;
        }
    }


    static void Main()
    {
        object res = new Test<MyEnum>(MyEnum.First);
        Console.WriteLine((MyEnum)(Test<MyEnum>)res);
        Console.WriteLine((MyEnum)res);
    }

First "Console.WriteLine" works OK. Second one fails.

Is there any way I can modify this behavior and get it working without double casting?

UPDATE 1

I must use object to value cast (in real application I have to cast ComboBox.SelectedItem property and I do not want to add extra property to ComboBox, because I'll have to change my UI interaction code everywhere).

UPDATE 2

Implicit conversions to and from System.Object are not allowed.

UPDATE 3

Updated my sample code to reflect the whole problem.

Don't use object that way. Write your first line like this instead:

Test res = new Test(1);

If you must have it in an object first, remember that all the compiler knows about it at this point is that it's an object, and nothing more. You, as the programmer, have additional information about what you expect this object to be, but for the compiler to take advantage of that information you have to put it into your code somewhere.

Update:
I'm glad I was able to find this again, because this almost-very-timely article by Eric Lippert, who works on the C# language design, went up this morning and explains the problem in depth:
http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx

If you want to simplify casting and not care performance effect, then create extension method.

public static T To<T>(this object obj) {
    Type type = obj.GetType();
    MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static);
    MethodInfo method = methods.FirstOrDefault(mi => (mi.Name == "op_Implicit" || mi.Name == "op_Explicit") && mi.ReturnType == typeof(T));
    if (method == null)
        throw new ArgumentException();
    return (T)method.Invoke(null, new[] { obj });
}

Usage

Console.WriteLine(res.To<MyEnum>());

Instead of adding implicit operators, consider implementing IConvertible . You only need to implement the ToInt32 method, the others are meaningless and you can throw the InvalidCastException in the other methods.

After that, you can use Convert.ToInt32() method to convert your object in one step.

or even

var res = new Test(1);

Your local variable res is always of type object; so the line that isn't working is trying to convert an object, that isn't an int, to an int, which can't be done. Same as this fails:

        object d = 5.5d;
        Console.WriteLine((int)d);

EDIT:

Perhaps a pattern that might help is something like this:

        if (res.GetType() == typeof(Test))
        {
            Console.WriteLine((int)(Test)res);
        }
        else
        {
            Console.WriteLine((int)res);
        }

It's a very localized solution to your problem, but perhaps it will work for you.

While the error is due to res being of type object, I would make the Test->int operator explicit...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM