如何在C#泛型类中调用类型转换运算符? [英] How to call type conversion operator in C# generic class?

查看:172
本文介绍了如何在C#泛型类中调用类型转换运算符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎我们不能在C#泛型类中轻松地调用类型转换运算符.这是代码.为什么?

It seems we cannot call type conversion operator easily in C# generic class. Here is the code. Why?

T006最终存档了我们的目标.

T006 finally archive our target.

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.Linq;

namespace ConsoleApplication1
{
    class vec<T, T2> : List<T> where T : class
    {
        public vec(IEnumerable<T2> other)
        {
            //Converter<T2, T> cvt = (v) => (T)v; // T004 failed, try defined function dynamicly, cannot compile, too.

            // T006 pass, client happy, we not happy, but anyway passed, performance may not happy.
            var conversionOperator = typeof(T).GetMethods(BindingFlags.Static | BindingFlags.Public)
                                    .Where(m => m.Name == "op_Explicit" || m.Name == "op_Implicit")
                                    .Where(m => m.ReturnType == typeof(T))
                                    .Where(m => m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(T2))
                                    .FirstOrDefault();
            Func<T2, T> cvt = (obj) =>
            {
                if (conversionOperator != null)
                    return (T)conversionOperator.Invoke(null, new object[] { obj });
                else
                    return default(T);
            };

            foreach (T2 item in other)
            {
                //Add((T)item);         // T001 failed, this line cannot compile
                //Add(item as T);       // T002 failed, this line alwasy return null. //  http://msdn.microsoft.com/en-us/library/vstudio/cscsdfbt.aspx
                //Add((T)(object)item); // T003 failed, pass compile, but throw exception at runtime.
                Add(cvt(item));         // T006 pass.
            }
        }

        // T005 pass, but clients for this code will not happy.
        public vec(Converter<T2, T> cvt, IEnumerable<T2> other)
        {
            foreach (T2 item in other)
            {
                Add(cvt(item));
            }

        }
    }

    class XXX
    {
        public int foo = 22;
        static public explicit operator XXX(YYY other)
        {
            XXX me = new XXX();
            me.foo = (int)other.foo;
            return me;
        }
    }

    class YYY
    {
        public float foo = 11;
    }



    class Program
    {
        static void Main(string[] args)
        {
            YYY[] from = new YYY[2];
            for (int i = 0; i < from.Length; i++)
            {
                from[i] = new YYY();
            }

            XXX x = (XXX)from[0];

            vec<XXX, YYY> coll = new vec<XXX, YYY>(from);

            // Not happy, this requires user have strong C# skill;
            //vec<XXX, YYY> coll = new vec<XXX, YYY>((v) => (XXX)v, from);

            foreach (var item in coll)
            {
                Debug.Print("Value is {0}", item.foo);
            }

        }
    }

}

T001的编译器错误是:Cannot convert type 'T2' to 'T'

The compiler error for T001 is: Cannot convert type 'T2' to 'T'

推荐答案

如果您需要运行自定义的隐式/显式转换运算符,则将其强制转换为object(或从object执行) as强制转换)将跳过它们,因为只有在执行运行时强制转换时才在编译时才知道该信息.

If you need to have your custom implicit/explicit conversion operators run, then casting to/from object (or performing an as cast) will skip them because the information is only known at compile-time when you are performing a runtime cast.

通过您所发布的通用通用方法,我知道的唯一方法是利用dynamic,它将在运行时查找以查看是否定义了任何转换运算符并调用它们:

The only way I know of, through a general-use generic method such as you posted, is to leverage dynamic which will lookup at runtime to see if there are any conversion operators defined and call them:

return (T2)(dynamic)obj;

简单示例:

public class Class1
{

    public static implicit operator Class1(Class2 class2)
    {
        Console.WriteLine("implicit conversion from Class2 to Class1");
        return new Class1();
    }

    public static implicit operator Class2(Class1 class1)
    {
    Console.WriteLine("implicit conversion from Class1 to Class2");
        return new Class2();
    }
}

public class Class2
{

}

public static T2 Convert<T1, T2>(T1 obj)
{
    return (T2)(dynamic)obj;
}

var class1 = new Class1();
var class2 = Convert<Class1, Class2>(class1);
//outputs: implicit conversion from Class1 to Class2

但是请注意,这是使用反射并在运行时进行了大量工作的,因此请进行彻底的测试并确保性能仍然可以接受.

Be aware though, that this using reflection and doing significant work at runtime, so thoroughly test and make sure performance is still acceptable.

由于您无权访问动态语言运行时,因此可以使用反射来编写自己的转换操作符查找:

Since you do not have access to the dynamic language runtime, you can write your own conversion operator lookups with reflection:

public static T2 Convert<T1, T2>(T1 obj)
{
    var conversionOperator = typeof(T1).GetMethods(BindingFlags.Static | BindingFlags.Public)
    .Where(m => m.Name == "op_Explicit" || m.Name == "op_Implicit")
    .Where(m => m.ReturnType == typeof(T2))
    .Where(m => m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(T1))
    .FirstOrDefault();

    if (conversionOperator != null)
        return (T2)conversionOperator.Invoke(null, new object[]{obj});

    throw new Exception("No conversion operator found");
}

您可能需要调整代码(如果找不到操作符,则可能尝试进行传统的转换),而且我不确定是否可以保证每次都能正常工作.我不知道是否需要处理极端情况或平台怪癖.更不用说反射会很慢了.您可以引入一种快速缓存机制,在其中使用Dictionary进行O(1)查找,或者在其中存储每种类型的每种转换运算符的存储方式.

You may need to tweak the code (perhaps to attempt traditional casting if no operators are found), and I'm not sure if I can guarantee that this will work every time. I don't know if there are corner cases or platform quirks to handle. Not to mention that this will be pretty slow with the reflection. You could introduce a quick caching mechanism where you do an O(1) lookup with a Dictionary or something where you can store each conversion operator as they're found for each type combination.

这篇关于如何在C#泛型类中调用类型转换运算符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆