0

C# 4.0 を使用しています。MyBuffer<int>のインスタンスを のインスタンスに変換したいMyBuffer<float>。コンバーターは、他の基本型も処理できるように十分に汎用的でなければなりません。

これ(または同等のソリューション)が機能することを望みます。どうやって?

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

上記のコードには、解決する必要がある 2 つの主要な問題があります。

  1. 変数がの任意の値にType等しいかどうかをどのように判断しますか?SomeType<T>T
  2. いくつかの変数にT設定してテンプレート化された関数を呼び出すことは可能ですか?Type
4

3 に答える 3

4

ラップするバッファーを引数として受け取るコンストラクターが非常に便利に含まれているためMyBuffer<T>、1 つのバッファーを別のバッファーに手動で変換し (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の懸念を和らげるために、質問が尋ねていることを反映して実行する方法を次に示しますが、ランタイムがあなたの代わりに掘り下げるより便利な形式です。

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ということは、この特定の配列がラムダなどと混合することができず、実行時にリフレクションと同等の道徳的処理がまだ行われていることを意味します (表示されないだけです)。ですから、タダのランチというわけではありませんが、時には役立つこともあります。

于 2013-05-02T12:24:45.367 に答える
1

最初の問題に:

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

2番目の問題に:

//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);
}
于 2013-05-02T20:23:40.457 に答える
1

これをそこに捨てるだけです。AutoMapper と呼ばれるオブジェクト タイプを変換するための優れたライブラリがあります。

http://automapper.codeplex.com/

于 2013-05-02T22:28:50.023 に答える