Generic method to type casting

前端 未结 8 1117
不思量自难忘°
不思量自难忘° 2021-02-02 11:55

I\'m trying to write generic method to cast types. I want write something like Cast.To(variable) instead of (Type) variable. My wrong versi

相关标签:
8条回答
  • 2021-02-02 12:06

    All of what's been said about the operator resolution is correct...but this is my answer to your main question:

        public static T To<T>(this object o)
        {
            return (T)(dynamic)o;
        }
    

    The key here is that casting o to dynamic will force the .NET to search for the explicit operator at runtime.

    Plus, why not make it an extension method?

    Instead of

            A a = new A();
            B b = Cast.To<B>(a);
    

    you can do

            A a = new A();
            B b = a.To<B>();
    

    An added benefit of exposing it as an extension method is that you gain a fluent interface for explicit casting (if you like that sort of thing). I've always hated the amount of nested parenthesis balancing required for explicit casting in .NET.

    So you can do:

    a.To<B>().DoSomething().To<C>().DoSomethingElse() 
    

    instead of

    ((C)((B)a).DoSomething())).DoSomethingElse()
    

    which, to me, looks clearer.

    0 讨论(0)
  • 2021-02-02 12:06

    Your Cast.To<T>() is just trying to interpret reference to given object as reference to T. Which fails of course.

    And if compiler encounters (B) a and knows that a is of type A and type A has compile-time cast operator to type B - it emits this cast. It is not your case.

    0 讨论(0)
  • 2021-02-02 12:19

    You can do this trick by finding the right methods through Reflection:

    public static T To<T> (object obj)
    {
        Type sourceType = obj.GetType ();
        MethodInfo op = sourceType.GetMethods ()
                        .Where (m => m.ReturnType == typeof (T))
                        .Where (m => m.Name == "op_Implicit" || m.Name == "op_Explicit")
                        .FirstOrDefault();
    
        return (op != null)
            ? (T) op.Invoke (null, new [] { obj })
            : (T) Convert.ChangeType (obj, typeof (T));
    }
    

    In .NET 4.0, you can use dynamic keyword as suggested in other answers.

    0 讨论(0)
  • 2021-02-02 12:20

    Maybe not what you what to do exactly, but that will works:

    public class Cast
    {
        public static targetType To<soureType, targetType>(object o)
        {
            return (targetType)((sourceType) o);
        }
    }
    

    But well, such a method seems useless to me...

    0 讨论(0)
  • 2021-02-02 12:21

    I've actually encountered this problem more than once and it doesn't feel as OOP "dirty" when I can limit myself to types implementing the IConvertible interface. Then the solution actually becomes very clean!

    private T To<T>(object o) where T : IConvertible
    {
        return (T)Convert.ChangeType(o, typeof(T));
    }
    

    I've used a variation of this when I for example wrote a tokenizer, where the input was a string, but where the tokens could be interpreted as both strings, integers, and doubles.

    Since it's using the Convert class, the compiler will actually have information to know what to do. It's not just a simple cast.

    If you need an even more generic way of casting, I have to wonder if this is not rather a design problem in code. I think a problem with broadening the scope for these things, is that the more areas you try to cover, the harder it will be for an outsider to know how much the method can do.

    I think it's of utmost importance that the casting actually works out when someone has specifically written a method for the job to avoid a situation like Add(x, y) for only certain values of x and y.

    I think the expectation is different if you try the casting yourself, as in T1 x = (T1) T2 y. Then I think it's more apparent that you're truly on your own, since you just made up some cast rather than called a "cover all casts method".

    In this case, it's clear that it's specifically dealing with objects implementing IConvertible and the developer can assume it'll work well with any of these objects.

    Maybe an object oriented-philosophy heavy answer that not everyone will even agree with, but I think these kinds of "conceptual questions" often end up in programming philosophy.

    0 讨论(0)
  • 2021-02-02 12:22

    If you can use c# 4.0 this works:

    namespace CastTest
    {
        internal class Program
        {
            private static void Main(string[] args)
            {
    
                A a = new A();
                B b = Cast.To<B>(a);
                b.Test();
    
                Console.Write("Done.");
                Console.ReadKey();
            }
    
            public class Cast
            {
                public static T To<T>(dynamic o)
                {
                    return (T)o;
                }
            }
    
            public class A
            {
                public static explicit operator B(A a)
                {
                    return new B();
                }
            }
    
            public class B
            {
                public void Test()
                {
                    Console.WriteLine("It worked!");
                }
            }
    
        }
    }
    
    0 讨论(0)
提交回复
热议问题