记录一些开发csharp时遇到的问题以及解决方案。
注意隐式转换与构造函数的冲突问题
因为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); }
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>' { } .class public auto ansi beforefieldinit CustomType extends [mscorlib]System.Object { .class nested public auto ansi sealed declf extends [mscorlib]System.MulticastDelegate { .method public hidebysig specialname rtspecialname instance void .ctor ( object 'object' , native int 'method' ) runtime managed { } .method public hidebysig newslot virtual instance float32 Invoke ( float32 x, float32 y ) runtime managed { } .method public hidebysig newslot virtual instance class [mscorlib ]System.IAsyncResult BeginInvoke ( float32 x , float32 y , class [mscorlib ]System.AsyncCallback callback , object 'object ' ) runtime managed { } .method public hidebysig newslot virtual instance float32 EndInvoke ( class [mscorlib]System.IAsyncResult result ) runtime managed { } } .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } }
接下来就照葫芦画瓢把这个类的定义给生成出来,然后我们再用这个定义的类型拿去
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;****
dotnet test
crash时的解决方案
开启--blame以及--blame-crash
或者通过环境变量开启dump。 export DOTNET_DbgEnableMiniDump=1export DOTNET_DbgMiniDumpType=4export DOTNET_DbgMiniDumpName=/tmp/crash_%p.dmp
通过lldb+sos插件调试core dump.
比如lldb exec -c xx.dmp
。
这个exec可以是python或者dotnet。
安装dotnet sos,参考
dotnet tool install --global dotnet-sos
dotnet tool install -g dotnet-symbol
dotnet sos install
sudo cp /Applications/Xcode.app/Contents/Developer/usr/bin/lldb /usr/local/bin sudo install_name_tool -add_rpath /Applications/Xcode.app/Contents/SharedFrameworks /usr/local/bin/lldb sudo codesign --force --sign - /usr/local/bin/lldb
然后用这个/usr/local/bin/lldb
进行调试, 要注意使用的这里的命令
才能看到csharp中的内容。
比如把bt
替换成dumpstack
P/invoke中使用AddressSanitizer
我需要调试ffi中的内存引用问题: 1.
首先编译时开启-fsanitize=address -g
, 注意得编译为动态库。
2. 在macos中,可以在xcode中找到asan的动态库:
❯ find /Applications/Xcode.app -name '*libclang_rt.asan*osx_dynamic.dylib' /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/17/lib/darwin/libclang_rt.asan_osx_dynamic.dylib
声明环境变量export DYLD_INSERT_LIBRARIES=$ASAN_LIB
,并执行代码