2

csharp中的小坑

 2 years ago
source link: https://zhen8838.github.io/2021/10/26/csharp-trick/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

最近重度使用csharp, 在写egraph中的图匹配, 简单记录一下遇到的一些小问题.

0x00 注意隐式转换与构造函数的冲突问题

因为cshapr每次都要写new,所以添加了一些隐式类型转换语法糖. 但是下面的代码就会出现问题, 就是new WildCardPattern(Name)这里其实并不是调用默认的WildCardPattern(string Name, ExprPattern? Pattern), 而是又被隐式类型转换成了WildCardPattern然后准备调用复制构造函数构造,但是隐式类型转换的时候就陷入递归了.

public sealed record WildCardPattern(string Name, ExprPattern? Pattern) : ExprPattern
{
private static int _globalCardIndex = 0;

public WildCardPattern() : this($"wc_{_globalCardIndex++}", null)
{
}

public static implicit operator WildCardPattern(string Name) => new WildCardPattern(Name);

public override bool MatchLeaf(Expr expr) => (Pattern?.MatchLeaf(expr) ?? true) && MatchCheckedType(expr);
}

0x01 C# delegate的本质

最近在弄一个直接jit生成代码然后用c#动态调用的东西,但是需要动态调用你必须要告诉当前的函数指针一个delegate的定义,不然c#就不知道你要输入什么返回什么. 那么既然是jit,我们的就不能提前写好这个定义, 所以需要动态构造一个delegate.

给定一个类:

public class CustomType
{
public delegate float declf(float x, float y);
}

他的delegate的修饰符并不是一种attr,而是一种表示他继承自MulticastDelegate, 所以你可以发现他的是一个NestedType,并且他的基类是MulticastDelegate.

var t = cls_type.GetNestedType("declf");
Assert.Equal(t.BaseType, typeof(MulticastDelegate));

同时他还具备了4个方法,其中一个是构造方法,以及三个重写的方法.

通过检查他的il我们可以发现declf就是个class,所以事情就简化成了构造这个类的问题.:

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi beforefieldinit CustomType
extends [mscorlib]System.Object
{
// Nested Types
.class nested public auto ansi sealed declf
extends [mscorlib]System.MulticastDelegate
{
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
object 'object',
native int 'method'
) runtime managed
{
} // end of method declf::.ctor

.method public hidebysig newslot virtual
instance float32 Invoke (
float32 x,
float32 y
) runtime managed
{
} // end of method declf::Invoke

.method public hidebysig newslot virtual
instance class [mscorlib]System.IAsyncResult BeginInvoke (
float32 x,
float32 y,
class [mscorlib]System.AsyncCallback callback,
object 'object'
) runtime managed
{
} // end of method declf::BeginInvoke

.method public hidebysig newslot virtual
instance float32 EndInvoke (
class [mscorlib]System.IAsyncResult result
) runtime managed
{
} // end of method declf::EndInvoke

} // end of class declf


// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Code size 7 (0x7)
.maxstack 8

IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method CustomType::.ctor

} // end of class CustomType

接下来就照葫芦画瓢把这个类的定义给生成出来,然后我们再用这个定义的类型拿去binding那个dll里面的函数,然后我们就可以动态的invoke生成的代码了~

AssemblyName aName = new AssemblyName("DynamicAssemblyExample");
AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndCollect);
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);
TypeBuilder tb = mb.DefineType("MyDynamicType", TypeAttributes.Public);
TypeBuilder nesttb = tb.DefineNestedType("DynamicDelegate", TypeAttributes.NestedPublic | TypeAttributes.Sealed, typeof(MulticastDelegate));
var ctor = nesttb.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard | CallingConventions.HasThis, new[] { typeof(object), typeof(IntPtr) });

ILGenerator ctorIL = ctor.GetILGenerator();
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_1);
ctorIL.Emit(OpCodes.Ret);

var invoke = nesttb.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot, CallingConventions.Standard | CallingConventions.HasThis, typeof(float), new[] { typeof(float), typeof(float) });
var beginInvoke = nesttb.DefineMethod("BeginInvoke", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot, CallingConventions.Standard | CallingConventions.HasThis, typeof(IAsyncResult), new[] { typeof(float), typeof(float), typeof(IAsyncResult), typeof(object) });

var endInvoke = nesttb.DefineMethod("EndInvoke", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot, CallingConventions.Standard | CallingConventions.HasThis, typeof(float), new[] { typeof(IAsyncResult) });
var created_class = tb.CreateType();
return created_class;




About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK