1

标题总结了它。我希望能够打电话

Foo f = getStruct<Foo>(..) 

并让该方法创建一个新的 Foo 对象(它将是一个结构),填充它并返回它?

另外,<T>类型的构造函数叫什么?我的谷歌搜索失败了,因为我确定我应该搜索什么..

此外,我知道所有可以创建的结构都有一个 .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

你需要一个结构工厂。

在这里,我使用了接口和包含结构的组合。如果固定字节结构很常见,那么我会为此创建一个结构,并将其包含在我定义的所有结构中。如果需要,您还可以设置接口以从泛型方法获得访问权限。

初始化仍由Activator对象处理,我确保始终通过Initialize()调用RawBuffer.

作为示例,我初始化了两个不同的结构,并计算了完成操作所需的滴答声。

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 回答
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 回答
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's,则添加泛型约束 struct将意味着您可以在不知道类型的情况下创建新结构。

如果要返回classes,则需要添加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 回答