Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/267.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在C中使用表达式访问结构属性#_C#_Struct_Linq Expressions_Propertyinfo - Fatal编程技术网

C# 在C中使用表达式访问结构属性#

C# 在C中使用表达式访问结构属性#,c#,struct,linq-expressions,propertyinfo,C#,Struct,Linq Expressions,Propertyinfo,我一直在使用以下代码缓存属性getter/setter委托,以便快速访问该功能: class PropertyHelper { public static Func<object, object> BuildGetter(PropertyInfo propertyInfo) { var method = propertyInfo.GetGetMethod(true); var obj = Expression.Parameter(ty

我一直在使用以下代码缓存属性getter/setter委托,以便快速访问该功能:

class PropertyHelper
{
    public static Func<object, object> BuildGetter(PropertyInfo propertyInfo)
    {
        var method = propertyInfo.GetGetMethod(true);

        var obj = Expression.Parameter(typeof(object), "o");
        Expression<Func<object, object>> expr =
                Expression.Lambda<Func<object, object>>(
                        Expression.Convert(
                                Expression.Call(
                                        Expression.Convert(obj, method.DeclaringType),
                                        method),
                                typeof(object)),
                        obj);
        return expr.Compile();
    }

    public static Action<object, object> BuildSetter(PropertyInfo propertyInfo)
    {
        var method = propertyInfo.GetSetMethod(true);

        var obj = Expression.Parameter(typeof(object), "o");
        var value = Expression.Parameter(typeof(object));

        Expression<Action<object, object>> expr =
            Expression.Lambda<Action<object, object>>(
                Expression.Call(
                    Expression.Convert(obj, method.DeclaringType),
                    method,
                    Expression.Convert(value, method.GetParameters()[0].ParameterType)),
                obj,
                value);

        Action<object, object> action = expr.Compile();
        return action;
    }
}
类属性帮助器
{
公共静态Func BuildGetter(PropertyInfo PropertyInfo)
{
var method=propertyInfo.getMethod(true);
var obj=表达式参数(typeof(object),“o”);
表达式表达式=
Lambda(
表达式。转换(
表情,打电话(
表达式.Convert(obj,方法.DeclaringType),
方法),
类型(对象)),
obj);
返回expr.Compile();
}
公共静态操作BuildSetter(PropertyInfo PropertyInfo)
{
var method=propertyInfo.GetSetMethod(true);
var obj=表达式参数(typeof(object),“o”);
var值=表达式参数(typeof(object));
表达式表达式=
Lambda(
表情,打电话(
表达式.Convert(obj,方法.DeclaringType),
方法,,
Expression.Convert(值,方法.GetParameters()[0].ParameterType)),
obj,
价值);
Action Action=expr.Compile();
返回动作;
}
}
这在访问类对象的属性时非常有效,但在我将其用于结构对象时失败。例如,考虑下面的代码:

public struct LocationStruct
{
    public double X { get; set; }
    public double Y { get; set; }
}

public class LocationClass
{
    public double X { get; set; }
    public double Y { get; set; }
}

public class Tester
{
    public static void TestSetX()
    {
        Type locationClassType = typeof(LocationClass);
        PropertyInfo xProperty = locationClassType.GetProperty("X");
        Action<object, object> setter = PropertyHelper.BuildSetter(xProperty);

        LocationStruct testLocationClass = new LocationClass();
        setter(testLocationClass, 10.0);
        if (testLocationClass.X == 10.0)
        {
            MessageBox.Show("Worked for the class!");
        }


        Type locationStructType = typeof(LocationStruct);
        xProperty = locationStructType.GetProperty("X");
        setter = PropertyHelper.BuildSetter(xProperty);

        LocationStruct testLocationStruct = new LocationStruct();
        setter(testLocationStruct, 10.0);
        if (testLocationStruct.X != 10.0)
        {
            MessageBox.Show("Didn't work for the struct!");
        }
    }
}
public struct LocationStruct
{
公共双X{get;set;}
公共双Y{get;set;}
}
公共类位置类
{
公共双X{get;set;}
公共双Y{get;set;}
}
公共类测试员
{
公共静态void TestSetX()
{
类型locationClassType=类型(LocationClass);
PropertyInfo xProperty=locationClassType.GetProperty(“X”);
Action setter=PropertyHelper.BuildSetter(xProperty);
LocationStruct testLocationClass=新的LocationClass();
设置器(testLocationClass,10.0);
if(testLocationClass.X==10.0)
{
Show(“为班级工作!”);
}
类型locationStructType=typeof(LocationStruct);
xProperty=locationStructType.GetProperty(“X”);
setter=PropertyHelper.BuildSetter(xProperty);
LocationStruct testLocationStruct=新的LocationStruct();
setter(testLocationStruct,10.0);
如果(testLocationStruct.X!=10.0)
{
Show(“对结构不起作用!”);
}
}
}
第一部分工作,将testLocationClass的X值设置为10。但是,由于LocationStruct是一个结构,testLocationStruct是通过值传入的,该值(委托调用的方法的内部)将其X设置为10,但上述代码块中的testLocationStruct对象保持不变

因此,我需要一种访问struct对象属性的方法,类似于上面的方法(它只适用于类对象的属性)。我曾尝试使用“通过引用传递”模式来实现这一点,但我就是无法让它工作


任何人都可以提供类似的BuffdDigter和Bu建dStter方法来缓存GETT属性值的GETT/SETER委托吗?

< P>结构,因为参数是通过值传递的,而REF/OUT似乎不能很好地使用表达式,可以考虑使用新的函数签名来代替Strut实例:

static Func<MethodInfo, object, object, object> s1 = (MethodInfo set, object instance, object val) =>
{
    set.Invoke(instance, new object[] { val });
    return instance;
};

// Non-Generic approach
static Func<object, object, object> BuildSetter5(PropertyInfo propertyInfo)
{
    var method = propertyInfo.GetSetMethod(true);

    var obj = Expression.Parameter(typeof(object), "o");
    var value = Expression.Parameter(typeof(object));

    Expression<Func<object, object, object>> expr =
        Expression.Lambda<Func<object, object, object>>(
            Expression.Call(
                s1.Method,
                Expression.Constant(method),
                obj,
                Expression.Convert(value, method.GetParameters()[0].ParameterType)),
            obj,
            value);

    Func<object, object, object> action = expr.Compile();
    return action;
}

// Generic approach
static Func<T, object, T> BuildSetter6<T>(PropertyInfo propertyInfo) where T : struct
{
    var method = propertyInfo.GetSetMethod(true);

    var obj = Expression.Parameter(typeof(T), "o");
    var value = Expression.Parameter(typeof(object));

    Expression<Func<T, object, T>> expr =
        Expression.Lambda<Func<T, object, T>>(
            Expression.Convert(
                Expression.Call(
                    s1.Method,
                    Expression.Constant(method),
                    Expression.Convert(obj, typeof(object)),
                    Expression.Convert(value, method.GetParameters()[0].ParameterType)),
                typeof(T)),
            obj,
            value);

    Func<T, object, T> action = expr.Compile();
    return action;
}
static Func s1=(MethodInfo集、对象实例、对象val)=>
{
调用(实例,新对象[]{val});
返回实例;
};
//非通用方法
静态Func BuildSetter5(PropertyInfo PropertyInfo)
{
var method=propertyInfo.GetSetMethod(true);
var obj=表达式参数(typeof(object),“o”);
var值=表达式参数(typeof(object));
表达式表达式=
Lambda(
表情,打电话(
s1.方法,
表达式。常数(方法),
obj,
Expression.Convert(值,方法.GetParameters()[0].ParameterType)),
obj,
价值);
Func action=expr.Compile();
返回动作;
}
//一般方法
静态Func BuildSetter6(PropertyInfo PropertyInfo),其中T:struct
{
var method=propertyInfo.GetSetMethod(true);
var obj=表达式参数(typeof(T),“o”);
var值=表达式参数(typeof(object));
表达式表达式=
Lambda(
表达式。转换(
表情,打电话(
s1.方法,
表达式。常数(方法),
Expression.Convert(obj,typeof(object)),
Expression.Convert(值,方法.GetParameters()[0].ParameterType)),
类型(T)),
obj,
价值);
Func action=expr.Compile();
返回动作;
}

您需要注意两件事才能使其正常工作:

  • 创建setter表达式树时,需要对值类型使用
    expression.Unbox
    ,对引用类型使用
    expression.Convert
  • 使用值类型调用setter时,需要确保已将其装箱,以便使用指向结构的指针设置值(而不是使用结构的副本)
  • 新的实现如下所示(仅显示新的setter和测试方法,因为其余的都是相同的):

    这张照片是:

    Worked for the class!
    Worked for the struct!
    
    我还准备了一个.Net fiddle,在这里显示了工作实现:


    有关
    表达式的解释,请参见此答案。Unbox
    步骤:

    快速注意:这些不是lambda表达式,只是表达式或表达式树。lambda更多地涉及闭包,即C#.Rgr中的匿名函数。。。谢谢你的留言。我会改变我的头衔和身份
    ...
    Type locationStructType = typeof (LocationStruct);
    xProperty = locationStructType.GetProperty("X");
    setter = PropertyHelper.BuildSetter(xProperty);
    LocationStruct testLocationStruct = new LocationStruct();
    
    // Note the boxing of the struct before calling the setter
    object boxedStruct = testLocationStruct;
    setter(boxedStruct, 10.0);
    testLocationStruct = (LocationStruct)boxedStruct;
    ...
    
    Worked for the class!
    Worked for the struct!