C#Emit,如何编写if语句 [英] C# Emit , how to write a if statement

查看:90
本文介绍了C#Emit,如何编写if语句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我有一堂课

    internal class Parent
    {
        protected void Write(string message, [CallerMemberName] string caller = null)
        {
            Console.WriteLine($"{caller} :: {message}");
        }
    }

并且我想动态创建一个类,该类具有属性名称",如果属性值更改,则调用write方法,看起来像

and i want to dynamic create a class , the class has a property "Name", if the property value changed then call write method , looks like

    class Child : Parent
    {
        private string _name;

        public string Name
        {
            get { return _name; }
            set
            {

                if (_name != value)
                {
                    Write("changedto: " + value);
                    _name = value;
                }

            }
        }
    }

我想知道的是高亮子句. 如何将其写入. 请帮忙.

what i want to know is the highlight clause. how to write it in emit. please help.

我想要下面的代码

     private static MethodBuilder BuildSetter(TypeBuilder typeBuilder, PropertyInfo property, FieldBuilder fieldBuilder, MethodAttributes attributes)
    {
        var setterBuilder = typeBuilder.DefineMethod($"set_{property.Name}", attributes, null, new Type[] { property.PropertyType });
        var ilGenerator = setterBuilder.GetILGenerator();

        ilGenerator.Emit(OpCodes.Ldarg_0);  //this
        ilGenerator.Emit(OpCodes.Ldarg_1);  // the first one in arguments list

            //code should be here

        ilGenerator.Emit(OpCodes.Stfld, fieldBuilder);
        ilGenerator.Emit(OpCodes.Ret);

        return setterBuilder;
    }


已更新

var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public,typeof(PropertyChanged));


var t = typeof(PropertyChanged);

var m2 = t.GetMethod("ValueChanged");

您看到的是,当我创建类型时,我使用的是父类型,而在父类型中,有一个名为"ValueChanged"的方法

you see , when i create the type , i use a Parent type , and in the parent type there is a method called "ValueChanged"

protected void ValueChanged(object value,[CallerMemberName] string property = null)

我想在set方法中调用它.

i want call it in set method.

更新2

private static MethodBuilder BuildSetter(TypeBuilder typeBuilder, PropertyInfo property, FieldBuilder fieldBuilder, MethodAttributes attributes)
{
    var propertyType = property.PropertyType;
    var setterBuilder = typeBuilder.DefineMethod($"set_{property.Name}", attributes, null, new Type[] { propertyType });

    var setIl = setterBuilder.GetILGenerator();
    Label exitSet = setIl.DefineLabel(); // define label to jump in case condition is false
    setIl.Emit(OpCodes.Ldarg_0); // this
    setIl.Emit(OpCodes.Ldfld, fieldBuilder); // _name field
    setIl.Emit(OpCodes.Ldarg_1); // value

    var inequality = propertyType.GetMethod("Equals", new[] { propertyType});
    setIl.Emit(OpCodes.Callvirt, inequality); // '!=' method
    setIl.Emit(OpCodes.Brtrue_S, exitSet); // check for inequality


    setIl.Emit(OpCodes.Ldarg_0); // load string literal
    setIl.Emit(OpCodes.Ldarg_1); // value
    setIl.Emit(OpCodes.Ldstr, property.Name);

    var m = typeBuilder.BaseType.GetMethod("ValueChanged", new Type[] {typeof(object),typeof(string) });

    setIl.Emit(OpCodes.Call, m);

    setIl.Emit(OpCodes.Ldarg_0); // this
    setIl.Emit(OpCodes.Ldarg_1); // value
    setIl.Emit(OpCodes.Stfld, fieldBuilder); // save the new value into _name
    setIl.MarkLabel(exitSet); // mark the label
    setIl.Emit(OpCodes.Ret); // return

    return setterBuilder;
}


更新3 屏幕快照


update 3 screen-snaps

更新4

也许,我已经找到错误原因,请参见反射发射和类型继承:调用基类型构造函数

maybe , i have found the error reason , see Reflection Emit and Type Inheritance: Calling Base Type Constructors

更新5

最后,我得到了错误原因.这不是我在更新4上猜到的,它是由调用parent't方法"ValueChanged"引起的.如果原始数据类型为 IsValueType ,则在将参数传输到方法之前,应将其作为对象装箱.参见下面的参考资料,

finally , i got the error reason . it was not what i guessed at update 4 , it was caused by calling parent't method "ValueChanged" . before we transfer the parameter to the method , we should Box it as Object if the original data type is IsValueType . see the reference below ,

C#发出,键入值比较

推荐答案

@AlbertK答案向您展示了正确的方法,我将添加完整的代码.希望对您有所帮助.

@AlbertK answer shows you the right way, I'll add the complete code. Hope it will help.

我将所有内容都放在一种方法中.按照您的意愿进行重构.

I put everything in one method.. refactor it as you wish.

// define assembly and module
var propertyName = "Name";
var propertyType = typeof(string);
var ab = AssemblyBuilder.DefineDynamicAssembly(
            new AssemblyName("dynamicAssembly"), 
            AssemblyBuilderAccess.Save);
var mb = ab.DefineDynamicModule("dynamicModule", "dynamicModule.dll");

// define type, field and property
var tb = mb.DefineType("dynamicType");
var fb = tb.DefineField("_name", propertyType, FieldAttributes.Private);
var pb = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, Type.EmptyTypes);
var get = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
var set = tb.DefineMethod("set_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new[] { propertyType });

// write the IL for the get method
var getIl = get.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0); // this
getIl.Emit(OpCodes.Ldfld, fb); // _name field
getIl.Emit(OpCodes.Ret);

// write the IL for the set method
var setIl = set.GetILGenerator();
Label exitSet = setIl.DefineLabel(); // define label to jump in case condition is false
setIl.Emit(OpCodes.Ldarg_0); // this
setIl.Emit(OpCodes.Ldfld, fb); // _name field
setIl.Emit(OpCodes.Ldarg_1); // value
var inequality = propertyType.GetMethod("op_Inequality", new[] { propertyType, propertyType });
setIl.Emit(OpCodes.Call, inequality); // '!=' method
setIl.Emit(OpCodes.Brfalse_S, exitSet); // check for inequality
setIl.Emit(OpCodes.Ldstr, "changedto:"); // load string literal
setIl.Emit(OpCodes.Ldarg_1); // value
var concat = propertyType.GetMethod("Concat", new[] { propertyType, propertyType });
setIl.Emit(OpCodes.Call, concat); // concat two strings (literal + value)
var writeline = typeof(Console).GetMethod("WriteLine", new[] { propertyType });
setIl.Emit(OpCodes.Call, writeline); // write
setIl.Emit(OpCodes.Ldarg_0); // this
setIl.Emit(OpCodes.Ldarg_1); // value
setIl.Emit(OpCodes.Stfld, fb); // save the new value into _name
setIl.MarkLabel(exitSet); // mark the label
setIl.Emit(OpCodes.Ret); // return
pb.SetGetMethod(get);
pb.SetSetMethod(set);

tb.CreateType(); // complete the type
ab.Save("dynamicModule.dll"); // save the assembly to disk

结果

internal class dynamicType
{
    private string _name;

    public string Name
    {
        get
        {
            return this._name;
        }
        set
        {
            if (this._name != value)
            {
                 Console.WriteLine("changedto:" + value);
                 this._name = value;
            }
        }
    }
}

这篇关于C#Emit,如何编写if语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆