1

タイトルはそれを要約しています。電話できるようになりたい

Foo f = getStruct<Foo>(..) 

メソッドで新しい Foo オブジェクト (構造体) を作成し、データを入力して返しますか?

また、 < T > 型のコンストラクターは何と呼ばれますか? 何を検索する必要があるのか​​ 確信があるため、Google検索が失敗しています..

さらに、作成できるすべての構造体に .raw フィールドがあることがわかっています。その .raw フィールドに入力できるようにしたいです。

これは本質的に私がやりたいことです。

    public T getStruct<T>(UInt32 sector) {
        <T> foo = new <T>;

        for (int i=0; i<100; i++) foo.raw[i]=0;
        return foo;
    }

構造体の形式は次のとおりです。

  StructLayout(LayoutKind.Explicit)]
  public unsafe struct RunBlock_t {
    [System.Runtime.InteropServices.FieldOffset(0)]  public fixed byte raw[512];
    [System.Runtime.InteropServices.FieldOffset(0)]  public UInt16 run_id;
    [System.Runtime.InteropServices.FieldOffset(2)]  public UInt16 magic;
    [System.Runtime.InteropServices.FieldOffset(510)]  public UInt16 checksum;
  }

この関数は、.raw ポインターとセクターを別の関数に渡します。別の関数はそのセクターをディスクからロードし、バイト単位で内容を .raw にコピーします。

このようにして、任意の構造体を作成し、ディスクからすばやく簡単にデータを取り込むことができます。これはあまり C# フレンドリーではありませんが、それを必要とする他の外部依存関係があります。

サンクス!

4

5 に答える 5

4

これがあなたが探しているものかどうかはわかりませんが、次のような一般的なメソッドを作成できます。

public static T GetStruct<T>() where T : struct //if T has to be struct
{
    return new T();
    //or return Activator.CreateInstance<T>();
}

編集:

Tプロパティ、フィールド、またはメソッドを使用する必要がある場合、コンパイル時にジェネリックを知っておく必要があるという点を本質的に見逃していると思います。T自分の意志が常にあることがわかっている場合はFoo、関数をジェネリックにする必要はありません。あなたはただ行うことができます:

public Foo getFoo(UInt32 sector)
{
    Foo foo = new Foo();

    for (int i=0; i<100; i++) foo.raw=0;
    return foo;
}

ただし、サブタイプがある場合はFoo、関数をジェネリックにするポイントがあります。このように:

public T getStruct<T>(UInt32 sector) where T : Foo
{
    T foo = new T();

    for (int i=0; i<100; i++) foo.raw=0;
    return foo;
}

これで、好みのタイプを指定して関数を呼び出すことができます。rawただし、そのためには、型で定義された関数が必要になりFooます。肝心なのは、オブジェクトの任意のメソッドを呼び出すことであり、コンパイル時に認識されている必要があります。それ以外の場合は、キーワードを使用する必要がありますがdynamic、これはほとんど悪い考えです。

于 2012-10-26T05:11:05.663 に答える
1

インターフェイスを作成する必要があります。

public interface IFoo
{
    int Raw { get; set; }
}

そして、すべての構造はこのインターフェースを実装する必要があります:

public struct Foo:IFoo
{
    [System.Runtime.InteropServices.FieldOffset(0)]  public fixed byte raw[512];
    public int Raw { get{return raw;} set{raw = value;} }
}  

そしてジェネリックメソッドを作成します:

 public static T GetStructs<T>(UInt32 sector) where T : struct, IFoo
        {
            var foo = new T {Raw = new int[sector]};
            for (var i = 0; i < 100; i++)
            {
                foo.Raw[i] = 0;
            }
            return foo;
        }

それを呼び出すには、次のコードを使用します。

var foo = getStructs<Foo>(32); 
于 2012-10-26T05:11:37.597 に答える
1

構造体ファクトリーが必要です。

ここでは、インターフェイスと含まれる構造体の組み合わせを使用しました。固定バイト構造体が一般的である場合は、その構造体を作成し、定義するすべての構造体で囲みます。必要に応じてジェネリック メソッドからアクセスできるようにインターフェイスを設定することもできます。

初期化は引き続きActivatorオブジェクトによって処理され、生のバイトは のInitialize()メソッドを呼び出すことによって常に初期化されるようにしRawBufferます。

例として、2 つの異なる構造体を初期化し、操作を完了するまでにかかるティックをカウントしました。

public interface IBlock
{
    RawBuffer Raw { get; }
}

[StructLayout(LayoutKind.Sequential)]
public unsafe struct RawBuffer
{
    public const int Count = 512;
    public const int Size = sizeof(byte) * Count;

    public fixed byte raw[Count];

    public void Initialize()
    {
        fixed (byte* ptr = raw)
        {
            for (int i = 0; i < Count; i++)
            {
                ptr[i] = 0;
            }
        }
    }
}

[StructLayout(LayoutKind.Explicit, Size = RawBuffer.Size)]
public unsafe struct RunBlock_t : IBlock
{
    [FieldOffset(0)] public RawBuffer raw;
    [FieldOffset(0)] public UInt16 run_id; 
    [FieldOffset(2)] public UInt16 magic; 
    [FieldOffset(510)] public UInt16 checksum;

    public RunBlock_t(UInt32 sector)
    {
        raw.Initialize();
        run_id = 0;
        magic = 0;
        checksum = 0;            
    }
    public RawBuffer Raw { get { return raw; } }
}
[StructLayout(LayoutKind.Explicit, Size=RawBuffer.Size)]
public unsafe struct RunBlock_s : IBlock
{
    [FieldOffset(0)] public RawBuffer raw;
    [FieldOffset(0)] public UInt16 run_id;
    [FieldOffset(2)] public UInt32 soup;
    [FieldOffset(510)] public UInt16 checksum;

    public RunBlock_s(UInt32 sector)
    {
        raw.Initialize();
        run_id = 0;
        soup = 0;
        checksum = 0;            
    }
    public RawBuffer Raw { get { return raw; } }
}

class Program
{

    public static T Factory<T>(UInt32 sector)
        where T : struct, IBlock
    {
        return (T)Activator.CreateInstance(typeof(T), sector);
    }

    static void Main(string[] args)
    {            
        var sw = Stopwatch.StartNew();
        var A = Factory<RunBlock_t>(0x20);
        long tic = sw.ElapsedTicks;

        Console.WriteLine("Initilized {0} in {1} cycles", A.GetType().Name, tic);
        // Initilized RunBlock_t in 1524 cycles


        sw = Stopwatch.StartNew();
        var B = Factory<RunBlock_s>(0x40);
        tic = sw.ElapsedTicks;

        Console.WriteLine("Initilized {0} in {1} cycles", B.GetType().Name, tic);
        // Initilized RunBlock_s in 722 cycles
    }
}
于 2012-10-26T05:17:41.867 に答える
0

作成はかなり簡単です。

public T GetStruct<T>()
{
    T myStruct = (T)Activator.CreateInstance<T>();
    return myStruct;
}

ただし、それを埋めたい場合は、少なくとも直接ではなく、内部のコンポーネントを認識していないため、ジェネリック メソッドを使用することはできません。リフレクションを使用しない限り...次のように:

using System.Reflection;

public T GetStruct<T>() where T : struct
{
    T myStruct = (T)Activator.CreateInstance<T>();

    FieldInfo[] infos = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
    foreach (FieldInfo info in infos)
    { 
        //Do something to fill the values;
        info.SetValue(myStruct, myValue);
    }

    return myStruct;
}
于 2012-10-26T05:20:10.233 に答える
0

のみを返したい場合は、ジェネリック制約structを追加すると、型を知らなくても新しい構造体を作成できることになります。 struct

esを返す場合は、制約classを追加する必要があります。new()

ジェネリック型にプロパティがあることを保証するため.rawに、インターフェイスをジェネリック制約として追加できます。

    public interface IMyInterface
    {
        int raw { get; set;  }
    }

    public static T GetStruct<T>(UInt32 sector) where T: struct , IMyInterface
    {
        var obj = new T();

        obj.raw = 0;

        return obj;
    }

制約により、プロパティがジェネリック型であることが保証されていることがobjわかります。IMyInterfaceraw

于 2012-10-26T05:20:14.790 に答える