简体   繁体   English

转换MyClass <SomeType> 到MyClass <SomeOtherType>

[英]Convert MyClass<SomeType> to MyClass<SomeOtherType>

Using C# 4.0. 使用C#4.0。 I want to convert an instance of MyBuffer<int> to an instance of MyBuffer<float> . 我想将MyBuffer<int>的实例转换为MyBuffer<float>的实例。 The converter must be general enough to handle other basic types too. 转换器必须足够通用才能处理其他基本类型。

I want this (or equivalent solution) to work. 我希望这个(或等效的解决方案)工作。 HOW? 怎么样?

var b1 = MyBuffer.Create(new int[100]);
var b2 = Convert.ChangeType(b1, typeof(MyBuffer<float>));
var b3 = Convert.ChangeType(b2, typeof(MyBuffer<byte>));

Consider the MyBuffer class: 考虑一下MyBuffer类:

public class MyBuffer
{
    public static MyBuffer<T> Create<T>(T[] buffer)
        where T : struct, IComparable, IConvertible
    {
        return new MyBuffer<T>(buffer);
    }
}

public class MyBuffer<T> : IConvertible
    where T : struct, IComparable, IConvertible
{
    public T[] Buffer
    {
        get;
        set;
    }

    public MyBuffer()
    {
    }

    public MyBuffer(T[] buffer)
    {
        Buffer = buffer;
    }

    public object ToType(Type conversionType, IFormatProvider provider)
    {
        if (conversionType == GetType())
            return this;

        // First problem: Determine if the type is MyBuffer<>.
        // if (conversionType == typeof(MyBuffer<>))
        {
            if (conversionType.IsGenericType && conversionType.GetGenericArguments().Length > 0)
            {
                var bufferType = conversionType.GetGenericArguments()[0];
                dynamic newBuffer = Buffer.
                    Select(s => Convert.ChangeType(s, bufferType))
                    .ToArray();

                // Second problem: Our dynamic variable will produce an exception here.
                return MyBuffer.Create(newBuffer);
            }
        }

        throw new InvalidCastException();
    }

    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    //
    // For completeness...
    //

    public TypeCode GetTypeCode()
    {
        throw new NotImplementedException();
    }

    public bool ToBoolean(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public byte ToByte(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public char ToChar(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public DateTime ToDateTime(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public decimal ToDecimal(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public double ToDouble(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public short ToInt16(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public int ToInt32(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public long ToInt64(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public sbyte ToSByte(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public float ToSingle(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public string ToString(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public ushort ToUInt16(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public uint ToUInt32(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }

    public ulong ToUInt64(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }
}

In my code above there are two major problems that need to be solved: 在上面的代码中,有两个主要问题需要解决:

  1. How do you determine if a Type variable equals SomeType<T> for an arbitrary value of T ? 你如何确定一个Type变量等于SomeType<T>为任意值T
  2. Is it possible to call a templated function with T set to some Type variable? 是否可以将T设置为某些Type变量来调用模板化函数?

Since MyBuffer<T> very helpfully includes a constructor that takes the buffer to wrap as an argument, you can simply convert one buffer to another manually (very easy with LINQ) and create a new "converted" instance: 由于MyBuffer<T>非常有用地包含一个构造器,该构造器将要包装的缓冲区作为参数,因此您可以简单地手动将一个缓冲区转换为另一个缓冲区(使用LINQ非常容易)并创建一个新的“转换后”实例:

var b1 = MyBuffer.Create(new int[100]);
var b2 = MyBuffer.Create(b1.Buffer.Select(i => (float)i).ToArray());

// another way to do the same:
var b3 = MyBuffer.Create(b1.Buffer.Select(Convert.ToSingle).ToArray());

Update: 更新:

In order to assuage Daniel 's concern that I might have hidden intentions, here is how to do what the question asks with reflection, but of the more convenient form where the runtime does the digging in your place: 为了减轻Daniel的担心,即我可能有隐藏的意图,这是如何通过反思来解决问题,但是在运行时代替您的情况下,更方便的形式是:

dynamic ConvertArray<T>(T[] input, Type target) {
    var result = Array.CreateInstance(target, input.Length);
    for (var i = 0; i < input.Length; ++i)
    {
        result.SetValue(Convert.ChangeType(input[i], target), i);
    }

    return result;
}

This method allows you to do this: 此方法使您可以执行以下操作:

var ints = new[] { 1, 2, 3 };
var strings = ConvertArray(ints, typeof(string));
foreach (var s in strings) {
    Console.WriteLine("[{0}] {1}", s.GetType(), s + " potato");
}

As is evident, strings behaves exactly like an array of strings. 显而易见, strings行为完全类似于字符串数组。 Of course being dynamic means that this particular array is never going to be able to mix with eg lambdas and the moral equivalent of reflection is still going on at runtime (only you don't see it). 当然, dynamic意味着该特定数组永远无法与lambda混合使用,并且在运行时仍在进行反射的道德等效(仅您看不到)。 So it's not quite a free lunch, but it can prove useful at times. 因此,这不是完全免费的午餐,但有时可能会有用。

To the first problem: 对于第一个问题:

if (conversionType.GetGenericTypeDefinition() == typeof(MyBuffer<>))

To the second problem: 对于第二个问题:

//your method....
//....
if (conversionType.IsGenericType && conversionType.GetGenericArguments().Length > 0)
{ //in fact you don't need this if in case the first problem is solved.

    var bufferType = conversionType.GetGenericArguments()[0];
    Func<MyBuffer<object>> AuxMethod = BufferConversion<object>;
    return AuxMethod.Method.GetGenericMethodDefinition().MakeGenericMethod(bufferType).Invoke(this, null);            
 }
//....continue your method....


private MyBuffer<NewType> BufferConversion<NewType>()
{
    NewType[] MyNewArray = Buffer.Select(s => (NewType)Convert.ChangeType(s, typeof(NewType))).ToArray();
    return MyBuffer.Create(MyNewArray);
}

Just throwing this out there. 只是把它扔在那里。 There is a great library for converting object types called AutoMapper. 有一个很棒的库,用于转换对象类型,称为AutoMapper。

http://automapper.codeplex.com/ http://automapper.codeplex.com/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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