如何在运行时从字符串中定义的一系列类型生成结构?
我有一个标题,例如包含“float,float,byte [255]”。 我有跟在这个标题后面的二进制数据,并按顺序保存数据。 在运行时读取头文件之前我不知道数据类型,我想生成一个结构,我可以用来将二进制数据编组成一个结构数组。
有什么想法吗?
答案 0 :(得分:3)
显然你知道你的应用程序的要求是什么,但正如lejon所说,问题是如何在创建它时访问该结构。在c#中,你必须跳过箍,而不是你不需要显式声明类型的vb。
我可以想到几种方法来实现你想要的。您可以使用CodeDom生成代码,请参阅此http://www.15seconds.com/issue/020917.htm
就个人简单的结构而言,我会按顺序构建代码
string szCode =@"using System;
using System.Windows.Forms;
namespace RunTimeCompile
{
[StructLayoutAttribute(LayoutKind.Sequential)]
public string MyStruct
{"
然后,对于头文件中的每个数据类型,将成员附加到szCode字符串。 (你需要构建一个基本函数来解析你的类型):
szCode += "float Field1;\n";
szCode += "float Field2;\n";
szCode += "byte[255] Field3;\n";
并关闭您的代码......
szeCode+=";\n;\n";
现在你有源代码使用CodeDom来编译它。
oCodeDomProvider = CodeDomProvider.CreateProvider("CSharp");
// Add what referenced assemblies
CompilerParameters oCompilerParameters = new CompilerParameters();
oCompilerParameters.ReferencedAssemblies.Add("system.dll");
// set the compiler to create a DLL
oCompilerParameters.GenerateExecutable = false;
// set the dll to be created in memory and not on the hard drive
oCompilerParameters.GenerateInMemory = true;
oCompilerResults =
oCodeDomProvider.CompileAssemblyFromSource(oCompilerParameters, szCode);
注意:您也可以使用CompileAssemblyFromFile从文件而不是内存源代码进行编译
现在在继续检查之前没有编译错误
if (oCompilerResults.Errors.Count!=0) return; // add you own error handling
现在您可以像这样
检索动态生成的结构的实例oAssembly = oCompilerResults.CompiledAssembly;
oObject = oAssembly.CreateInstance("RunTimeCompile.MyStruct");
oType = oObject.GetType();
现在,您可以读取二进制文件的所有行,并使用Marshal或您希望序列化二进制数据的任何其他方法(可能是二进制序列化程序)将它们编组为MyStruct []数组。
例如使用Runtime.Interop.Marshal你可以做这样的事情(你需要稍微调整一下,特别是你不能在你的代码中声明MyStruct [],所以你需要做一些像oObjectArray = oAssembly.CreateInstance(“RunTimeCompile.MyStruct []”)声明destValues结果数组):
byte[] sourceData = ReadSourceData(); // TODO: generate method to load your BLOB
MyStruct[] destValues = new MyStruct[Marshal.SizeOf(oType) + 1]
int arrayIndex = 0;
GCHandle handle = GCHandle.Alloc(sourceData, GCHandleType.Pinned);
try
{
IntPtr buffer = handle.AddrOfPinnedObject();
buffer = (IntPtr)(buffer.ToInt32() +
(arrayIndex*Marshal.SizeOf(typeof(MyStruct))));
destStruct = (MyStruct)Marshal.PtrToStructure(buffer, typeof(MyStruct));
}
finally
{
handle.Free();
}
return MyStruct;
现在你有了你的数组结构。
答案 1 :(得分:0)
问题是,一旦你定义了你的结构,你将如何访问它?您无法静态引用它,因为该类型仅适用于运行时。您可能必须使用反射,委托或dynamic
。有没有更好的方法来做你想要的事情(比如,一个单独的类接受字节数组并根据需要解释它)而不是在运行时生成结构?