- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有以下示例代码:
string a = "1";
int b = 0;
TypedReference tr = __makeref(b);
Int32.TryParse(a, out __refvalue(tr, int));
应该将 1 放入 b
。问题是,它抛出一个 BadImageFormatException: Bad class token
。问题当然是 out __refvalue(tr, int)
表达式。 __refvalue
被编译为 refanyval
操作码,它应该返回存储在类型化引用中的地址。 out
(同样适用于 ref
)关键字然后应该将其转换为 ref int
并将(未更改的)引用传递给 TryParse
方法。
问题出在IL:
.locals init (string V_0, int32 V_1, typedref V_2)
IL_0000: ldstr "1"
IL_0005: stloc.0
IL_0006: ldc.i4.0
IL_0007: stloc.1
IL_0008: ldloca.s V_1
IL_000a: mkrefany [mscorlib]System.Int32
IL_000f: stloc.2
IL_0010: ldloc.0
IL_0011: ldloc.2
IL_0012: refanyval 0
IL_0017: call bool [mscorlib]System.Int32::TryParse(string, int32&)
IL_001c: pop
现在问题很明显 - refanyval 0
。操作码应该采用类型参数,因此 0
完全不合适,它应该是 refanyval [mscorlib]System.Int32
。
这是编译器中的错误吗?有什么方法可以绕过这个错误吗?感谢您的意见。
编辑:所以我构建了一个生成 IL 的好方法,允许在 TypedReference
和 ref T
之间进行转换:
public static class ReferenceHelper
{
public delegate TResult OutDelegate<TArg,TResult>(out TArg variable);
public delegate TResult RefDelegate<TArg,TResult>(ref TArg variable);
public delegate void OutDelegate<TArg>(out TArg variable);
public delegate void RefDelegate<TArg>(ref TArg variable);
static readonly AssemblyBuilder ab;
static readonly ModuleBuilder mob;
static readonly Type TypedReferenceType = typeof(TypedReference);
static ReferenceHelper()
{
ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("ReferenceHelperAssembly"), AssemblyBuilderAccess.Run);
mob = ab.DefineDynamicModule("ReferenceHelperAssembly.dll");
}
public static TResult PassReference<TArg,TResult>(TypedReference tref, RefDelegate<TArg,TResult> del)
{
return ReferenceBuilder<TArg,TResult>.PassRef(tref, del);
}
public static void PassReference<TArg>(TypedReference tref, RefDelegate<TArg> del)
{
ReferenceBuilder<TArg>.PassRef(tref, del);
}
public static TResult PassReference<TArg,TResult>(TypedReference tref, OutDelegate<TArg,TResult> del)
{
return PassReference<TArg,TResult>(tref, delegate(ref TArg arg){return del(out arg);});
}
public static void PassReference<TArg>(TypedReference tref, OutDelegate<TArg> del)
{
PassReference<TArg>(tref, delegate(ref TArg arg){del(out arg);});
}
static int mcounter = 0;
private static Type BuildPassRef(Type deltype, Type argType, Type resultType)
{
TypeBuilder tb = mob.DefineType("ReferenceHelperType"+(mcounter++), TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract);
MethodBuilder mb = tb.DefineMethod(
"PassRef",
MethodAttributes.Public | MethodAttributes.Static,
resultType,
new[]{TypedReferenceType, deltype}
);
var il = mb.GetILGenerator();
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Refanyval, argType);
il.Emit(OpCodes.Callvirt, deltype.GetMethod("Invoke"));
il.Emit(OpCodes.Ret);
return tb.CreateType();
}
private static class ReferenceBuilder<TArg,TResult>
{
public delegate TResult PassRefDelegate(TypedReference tref, RefDelegate<TArg,TResult> del);
public static readonly PassRefDelegate PassRef;
static ReferenceBuilder()
{
Type t = BuildPassRef(typeof(RefDelegate<TArg,TResult>), typeof(TArg), typeof(TResult));
PassRef = (PassRefDelegate)t.GetMethod("PassRef").CreateDelegate(typeof(PassRefDelegate));
}
}
private static class ReferenceBuilder<TArg>
{
public delegate void PassRefDelegate(TypedReference tref, RefDelegate<TArg> del);
public static readonly PassRefDelegate PassRef;
static ReferenceBuilder()
{
Type t = BuildPassRef(typeof(RefDelegate<TArg>), typeof(TArg), typeof(void));
PassRef = (PassRefDelegate)t.GetMethod("PassRef").CreateDelegate(typeof(PassRefDelegate));
}
}
}
用法
string a = "1";
int b = 0;
TypedReference tr = __makeref(b);
ReferenceHelper.PassReference(tr, delegate(out int val){return Int32.TryParse(a, out val);});
最佳答案
问题是out
——编译器不知道如何正确编译out __refvalue
(或ref __refvalue
,就此而言) ),这并不奇怪,因为 __refvalue
支持的特性 (varargs) 不需要与 out
结合使用。从编译器不应该发出无效代码的意义上讲,这是一个错误;从某种意义上说,这不是错误,如果您使用未记录的关键字,那您就只能靠自己了(如果 Connect 票证有任何迹象,MS 对修复因使用它们而导致的错误不感兴趣)。
任何解决方法都涉及不使用 out
参数,但这是否可能取决于您的场景(您可以围绕 Int32.TryParse
编写一个返回元组的包装器例如,而不是或将参数框起来,但这当然是一个简化的实例)。更好的解决方法是不使用未记录的关键字——您可能不得不硬着头皮进行动态 IL 生成(然后我无法想象您需要 mkrefany
/refanyval
).
关于c# - 对 ref T 的 TypedReference 抛出 BadImageFormatException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26927782/
TypedReference 有什么实际用途吗?您实际会在实际代码中使用的结构? 编辑:.Net 框架在 Console.WriteLine 和 String.Concat 的重载中使用它们,它们从
我终于明白了 TypedReference.MakeTypedReference 的用法了方法,但为什么论点如此有限?底层的 private InternalMakeTypedReference(vo
我想假设这个问题的目的是检查是否至少有一种方法,即使是通过最不安全的 hack,来保持对非 blittable 值类型的引用。我知道这种设计类型堪比犯罪;除了学习之外,我不会在任何实际情况下使用它。所
警告:这个问题有点邪门……信教的程序员一向恪守优良作法,请勿阅读。 :) 有谁知道为什么使用TypedReference如此气馁(隐含地,由于缺乏文档)? 我发现它有很好的用途,例如当通过不应该是通用
我有以下示例代码: string a = "1"; int b = 0; TypedReference tr = __makeref(b); Int32.TryParse(a, out __refva
我是一名优秀的程序员,十分优秀!