当前位置: 首页 > 编程语言 > C#

使用LayoutKind.Explicit进行布尔编组,这是否损坏或设计失败?Share

时间:2023-04-11 00:33:24 C#

使用LayoutKind.Explicit的布尔编组,这是否损坏或设计失败?首先,布尔类型被称为具有四字节值的默认封送处理类型。以下代码有效:structA{publicboolbValue1;公共intiValue2;}结构B{publicintiValue1;公共布尔bValue2;}publicstaticvoidMain(){int[]rawvalues=newint[]{2,4};Aa=(A)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues,GCHandleType.Pinned).AddrOfPinnedObject(),typeof(A));Assert.IsTrue(a.bValue1==true);Assert.IsTrue(a.iValue2==4);Bb=(B)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues,GCHandleType.Pinned).AddrOfPinnedObject(),typeof(B));Assert.IsTrue(b.iValue1==2);断言。IsTrue(b.bValue2==true);显然,独立编组这些结构会很好。值按预期转换。但是,当我们将这些结构组合成一个“联合”时,通过声明LayoutKind.Explicit,如下所示:[StructLayout(LayoutKind.Explicit)]structBroken{[FieldOffset(0)]publicAa;[FieldOffset(0)]publicBb;我们突然发现自己无法正确编组这些类型。下面是上面结构的测试代码以及??它是如何失败的:int[]rawvalues=newint[]{2,4};破碎破碎=(破碎)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues,GCHandleType.Pinned).AddrOfPinnedObject(),typeof(Broken));Assert.IsTrue(broken.a.bValue1!=false);//通过,不为假Assert.IsTrue(broken.a.bValue1==true);//通过,必须为真?Assert.IsTrue(true.Equals(broken.a.bValue1));//失败,哇,WTF?Assert.IsTrue(broken.a.iValue2==4);//失败,a.iValue1==1,4发生了什么?Assert.IsTrue(broken.b.iValue1==2);//passAssert.IsTrue(broken.b.bValue2==true);//pass看到这个表达式很幽默true:(a.bValue1!=false&&a.bValue1==true&&!true.Equals(a.bValue1))当然,这里更大的问题是a.iValue2!=4,并且4变为1(可能是通过重叠bool)。所以问题是:这是一个错误,还是设计失败?背景:这来自What'sthedifferencebetweenastructcontainingaboolvsauintwhenusingPInvoke?更新:当您使用大整数值(>255)时,这甚至更奇怪,因为只有用于布尔值的字节被修改为1,从而将b.bValue2的0x0f00更改为0x0f01。对于上面的a.bValue1,它根本不翻译,0x0f00为a.bValue1提供了一个错误的值。更新#2:上述问题最明显和合理的解决方案是使用uint进行编组并公开布尔属性。用“解决方法”实际解决问题不是问题。我主要想知道这是一个错误还是您期望的这种行为?structA{privateuint_bValue1;publicboolbValue1{get{return_bValue1!=0;}}publicintiValue2;}结构B{publicintiValue1;私人单位_bValue2;它按设计工作。发生的情况如下:获取newint[]{2,4}并让它编组A、B、Broken和Broken2。最后一个和Broken一样,但是字段的顺序是相反的(先是b,然后是a)。如果我们将int编组到这些结构中,我们在内存中得到以下值:那么会发生以下情况:所以对于A,第一个int转换为1,对于B,第二个int转换为1,对于Broken,因为B是最后一个字段,它的规则适用,因此第二个int转换为1。类似于Broken2。这行评论'失败,哇,WTF?'由于执行布尔比较的方式而失败。它将2与1进行比较:IL_007e:ldc.i4.1IL_007f:ldloca.s3IL_0081:ldfldavaluetypeTest/ATest/Broken::aIL_0086:ldfldboolTest/A::bValue1IL_008b:ceqceq最后将1与比较bValue中的字节,即2。有趣的是,if(broken.a.bValue1)将测试“true”,因为它不为零。至于另一个问题(broken.a.iValue2==4),当我将[MarshalAs(UnmanagedType.Bool)]应用于结构中的两个布尔字段时,它就消失了。这确保布尔值被整理为整数(.NET中为4个字节)。似乎earlNameless是正确的,因为添加了另一个intstruct:structC{publicintiValue1;公共intiValue2;}到union的结尾似乎至少纠正了部分问题。然而,这仍然是有缺陷的,因为布尔值只考虑单字节值,而且证书不可靠。最后,我想到的最佳答案是使用自定义类型进行编组。这就是C#学习教程:使用LayoutKind.Explicit进行布尔编组,这是否已损坏或设计失败?所有分享的内容,如果对你有用,需要了解更多C#学习教程,希望大家多多关注——[Serializable][ComVisible(true)]publicstructBOOL:IComparable,IConvertible,IComparable,IEquatable,IComparable,IEquatable{privateuint_data;公共BOOL(布尔值){_data=值?1u:0u;}publicBOOL(intvalue){_data=unchecked((uint)value);}publicBOOL(uintvalue){_data=value;}privateboolValue{get{return_data!=0;}}privateIConvertibleConvertible{get{return_data!=0;}}#regionIComparableMemberspublicintCompareTo(objectobj){returnValue.CompareTo(obj);}#endregion#regionIConvertible成员publicTypeCodeGetTypeCode(){returnValue.GetTypeCode();}publicstringToString(IFormatProviderprovider){returnValue.ToString(provider);}boolIConvertible.ToBoolean(IFormatProviderprovider){returnConvertible.ToBoolean(provider);}byteIConvertible.ToByte(IFormatProviderprovider){returnConvertible.ToByte(提供者);}charIConvertible.ToChar(IFormatProviderprovider){returnConvertible.ToChar(provider);}DateTimeIConvertible.ToDateTime(IFormatProviderprovider){returnConvertible.ToDateTime(provider);}十进制IConvertible.ToDecimal(IFormatProviderprovider){returnConvertible.ToDecimal(provider);}doubleIConvertible.ToDouble(IFormatProviderprovider){returnConvertible.ToDouble(provider);}shortIConvertible.ToInt16(IFormatProviderprovider){returnConvertible.ToInt16(provider);}intIConvertible.ToInt32(IFormatProviderprovider){returnConvertible.ToInt32(provider);}longIConvertible.ToInt64(IFormatProviderprovider){returnConvertible.ToInt64(provider);}sbyteIConvertible.ToSByte(IFormatProviderprovider){returnConvertible.ToSByte(provider);}floatIConvertible.ToSingle(IFormatProviderprovider){returnConvertible.ToSingle(provider);}ushortIConvertible.ToUInt16(IFormatProvider提供者){返回Convertible.ToUInt16(provider);}uintIConvertible.ToUInt32(IFormatProviderprovider){returnConvertible.ToUInt32(provider);}ulongIConvertible.ToUInt64(IFormatProviderprovider){returnConvertible.ToUInt64(provider);}objectIConvertible.ToType(TypeconversionType,IFormatProviderprovider){returnConvertible.ToType(conversionType,provider);}#endregion#regionIComparableMemberspublicintCompareTo(BOOLother){returnValue.CompareTo(other.Value);}publicintCompareTo(boolother){returnValue.CompareTo(other);}#endregion#regionIEquatable成员publicboolEquals(BOOLother){returnValue.Equals(other.Value);}publicboolEquals(boolother){returnValue.Equals(other);}#endregion#regionObjectOverridepublicoverridestringToString(){returnValue.ToString();}publicoverrideintGetHashCode(){returnValue.GetHashCode();}publicoverrideboolEquals(objectobj){returnValue.Equals(obj);}#endregi关于#region隐式/显式转换运算符publicstaticimplicitoperatorbool(BOOLvalue){returnvalue.Value;}publicstaticimplicitoperatorBOOL(boolvalue){returnnewBOOL(value);}publicstaticexplicitoperatorint(BOOLvalue){returnunchecked((int)value._data);}publicstaticexplicitoperatorBOOL(intvalue){returnnewBOOL(value);}publicstaticexplicitoperatoruint(BOOLvalue){returnvalue._data;}publicstaticexplicitoperatorBOOL(uintvalue){returnnewBOOL(value);}#endregion#region+,-,!,~,++,--,true,false一元运算符重载。publicstaticBOOLoperator!(BOOLb){returnnewBOOL(!b.Value);}publicstaticbooloperatortrue(BOOLb){returnb.Value;}publicstaticbooloperatorfalse(BOOLb){return!b.Value;}#endregion#region+,-,*,/,%,&,|,^,>二元运算符重载。publicstaticBOOLoperator&(BOOLb1,BOOLb2){returnnewBOOL(b1.Value&b2.Value);}publicstaticBOOL运算符|(BOOLb1,BOOLb2){returnnewBOOL(b1.Value|b2.Value);}#endregion#region==,!=,,=比较运算符重载publicstaticbooloperator==(BOOLb1,BOOLb2){return(b1.Value==b2.Value);}publicstaticbooloperator!=(BOOLb1,BOOLb2){return(b1.Value!=b2.Value);}#endregion}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如有转载请注明出处: