不同的结构属性基于32位或64位

7
有没有一种方法可以有条件地将属性应用于结构体?
如果机器是32位,我想应用此属性
[StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Unicode)]
如果机器是64位,我想应用此属性
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
或者,我可以在属性中替换值...
32位(Pack = 2)
[StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Unicode)]
64位(Pack = 8)
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)]
我尝试使用这个example,但它只适用于自定义属性,而不是现有属性。
更新:
  • 我想编译成“Any CPU”
  • 该属性适用于SHFILEOPSTRUCT,根据处理器使用其中之一。
  • 我不想编译两个版本。

1
你会静态编译64位和32位程序,还是使用“任何CPU”并希望在运行时表现不同? - Joachim Isaksson
如果 StructLayoutAttribute 类没有被密封就好了。唉! - simonlchilds
1
你也许可以使用条件编译指令来实现这个。 - Jeremy Holovacs
OK处理位数-正如@PhonicUK所建议的那样,可能有两个版本可以作为答案。(注意:进程仍可能是x86在x64操作系统上,而操作系统可能是x86在支持x64的机器上) - Alexei Levenkov
@Hans Passant我找到了这个链接,其中有两个声明:http://www.codeproject.com/Articles/3590/C-does-Shell-Part-2 - Rob
显示剩余4条评论
3个回答

6

很好的问题。

我首先想到的答案是预处理器指令和32位和64位编译后的程序集。您可以使用相同的代码,甚至是相同的项目,只需根据目标系统构建和部署两种方式:

#ifdef Bit32
[StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Unicode)]
#endif
#ifdef Bit64
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)]
#endif

这将需要根据目标架构为您的项目定义Bit32和Bit64编译常量,并可能需要构建您的应用程序两次。
如果您想在运行时执行此操作,除非您在运行时动态发出整个类,否则我认为这是不可能的。属性只能具有常量数据,并且不能在运行时有条件地应用(预处理器指令在编译时而不是运行时操作)。
我能想到的唯一另一种方法是将类定义复制到两个命名空间中,并基于Environment.Is64BitOperatingSystem属性有条件地使用其中一个或另一个。您可以使用此属性有条件地控制实例化哪个类,或选择哪种创建策略(使用哪种工厂方法或相关模式),但您无法在运行时有条件地控制属性;它们的信息作为元数据静态编译到程序集清单中。特别是这个属性被运行时本身用于定义它如何将对象的成员存储为堆数据,您从不真正在用户代码中查找此属性并使用它来定义行为(因此忽略或指定运行时的Pack值)。

这就像在卧室里被捆绑和掐住脖子一样有趣;肯定需要一定的心态来看待它。 - KeithS
是的,我应该更谨慎地选择我的措辞 - "有趣"指的是“令人兴奋、有趣、冒险但不太可能盈利”。我认为“束缚和窒息”是一个过于严峻的比喻,除非当然有人决定在真正的生产代码中采用这种方法。 - Alexei Levenkov
在这种情况下,接口能用吗? - Rob
是的,您可以将两个结构体都抽象到一个接口后面,然后将其中一个注入到任何用途中。 这将消除通过命名空间分离结构体的需要; 一个可以是MyBit64Struct而另一个可以是MyBit32Struct,只要所有用法都是它们共同的接口IMyStruct,您就可以得到想要的结果。 唯一可能的问题是您必须有某种工厂来生成IMyStructs; 用法不能“new”一个出来。 这很容易设置。 - KeithS

1
创建两个不同的构建目标(一个用于32位,一个用于64位),为每个添加一个条件编译符号(一个为x86,另一个为x86_64),并在结构定义周围使用#ifdef

没有更多的点赞了 :(.... 我认为这种方法会起作用 - 编译同一类/结构的两个版本,并根据当前进程的位数在运行时动态加载其中一个。这样,您就拥有一个结构/类,并且可以轻松地在其余代码中使用它,而不需要奇怪的ifdefs。 - Alexei Levenkov
@Alexei Levenkov - 应该说,我不想编译两个版本。 - Rob

0

我认为你不能这样做。只需有两个结构,并提供一种将两者转换为共享结构或类以进行处理的方法...

注意:您要求的功能非常奇怪(基于运行时发生的JIT类型的不同显式布局的结构)。在大多数情况下,这用于与某些独立于应用程序位数的知名固定协议匹配的字节的物理布局。您可以将您的情况视为具有x86 / x64情况下的2个不同的协议/互操作性,并对2个结构感到满意。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接