C# 基于字符串中定义的数据类型在运行时生成结构
如何在运行时从字符串中定义的类型序列生成结构 我有一个标题,例如包含“float,float,byte[255]”。 我在这个标题后面有二进制数据,并按顺序保存数据。 在运行时读取头文件之前,我不知道数据类型,我想生成一个结构,用于将二进制数据封送到结构数组中C# 基于字符串中定义的数据类型在运行时生成结构,c#,.net,C#,.net,如何在运行时从字符串中定义的类型序列生成结构 我有一个标题,例如包含“float,float,byte[255]”。 我在这个标题后面有二进制数据,并按顺序保存数据。 在运行时读取头文件之前,我不知道数据类型,我想生成一个结构,用于将二进制数据封送到结构数组中 有什么想法吗?问题是,一旦定义了结构,您将如何访问它?您不能静态引用它,因为该类型仅限于运行时。您必须使用反射、委托或动态。有没有更好的方法来做你想做的事情(比如,一个单独的类接受字节数组并根据需要解释它)而不是在运行时生成一个结构?显然
有什么想法吗?问题是,一旦定义了结构,您将如何访问它?您不能静态引用它,因为该类型仅限于运行时。您必须使用反射、委托或
动态
。有没有更好的方法来做你想做的事情(比如,一个单独的类接受字节数组并根据需要解释它)而不是在运行时生成一个结构?显然,你知道你的应用程序的要求是什么,但正如lejon所说,问题是一旦创建了结构,如何访问它。在c#中,您必须跳转,而vb则不需要显式声明类型
我可以想出几种方法来实现你的愿望。您可以使用CodeDom生成代码,请参见
就个人而言,对于一个简单的结构,我会强制构造代码
string szCode =@"using System;
using System.Windows.Forms;
namespace RunTimeCompile
{
[StructLayoutAttribute(LayoutKind.Sequential)]
public string MyStruct
{"
然后,对于头文件中的每个数据类型,将成员附加到szCode字符串中。(您需要构建一个基本函数来解析您的类型):
关闭你的代码
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);
注意:您也可以使用CompileAseMblyFromFile从文件编译,而不是从内存中的源代码编译
现在,在继续检查之前,没有编译错误
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结果数组):
现在您有了结构数组。无论您在哪里使用该结构,都必须使用反射,确定没有更好的方法吗?似乎“在运行时生成结构”是建议的解决方案。。。您试图解决的真正问题是什么?如何解决,或者学习其他方法。您可以查看Expando对象,看看它是否有帮助:问题是,我必须迭代整个数据集,并单独解析每个数据类型。结构方式只需在内存中放入大量数据,并在其上应用解释“过滤器”。但一旦创建了结构,您将如何访问它?我不知道。通过反射创建“新”结构?如果我在运行时之前知道结构,但在编译时之后,我是否可以在执行时以某种方式将结构源动态编译到.exe中?您可以编写结构遵循的接口,然后创建实现该接口的结构。问题是结构的任何使用都会被装箱(因为接口是引用类型),动态创建结构将非常复杂。您最好编写一个单独的类来解释二进制数据,或者编写一个类的继承树来帮助您。我会考虑这个问题。谢谢
oAssembly = oCompilerResults.CompiledAssembly;
oObject = oAssembly.CreateInstance("RunTimeCompile.MyStruct");
oType = oObject.GetType();
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;