2013-05-02 105 views
0

使用C#4.0。我想将MyBuffer<int>的实例转换为MyBuffer<float>的实例。转换器必须足够通用以处理其他基本类型。将MyClass <SomeType>转换为MyClass <SomeOtherType>

我希望这个(或同等的解决方案)能够正常工作。怎么样?

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

考虑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(); 
    } 
} 

在我上面的代码有一些需要解决两个主要问题:

  1. 如何确定是否Type变量等于SomeType<T>的任意值为T
  2. 是否可以调用模板函数T设置为Type变量?

回答

4

由于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()); 

更新:

为了缓和Daniel的关注,我可能有不可告人的意图,这里是如何做的问题询问与反思什么,但对更方便m其中运行时不挖你的地方:

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; 
} 

这种方法可以让你做到这一点:

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"); 
} 

很明显,strings行为完全像一个字符串数组。当然是dynamic意味着这个特定的阵列将永远不能与例如lambdas和反射的道德等价物仍然在运行时发生(只有你没有看到它)。所以这不是一顿免费的午餐,但有时候它会证明是有用的。

+0

是的,但我想解决一个更普遍的问题。给定一个“SomeClass ”的实例,你如何将它转换为同一类,但是具有不同类型的“T”? – l33t 2013-05-02 12:37:03

+1

@ l33t由于可能的转换是有限的,您希望如何解决这两种类型的问题? – 2013-05-02 12:43:05

+0

任何基本类型; 'byte','int','short','float','double'和它们的有符号/无符号对应。也许也是'布尔'。 – l33t 2013-05-02 12:45:24

1

第一个问题:

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

第二个问题:

//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); 
} 
相关问题