Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jsp/3.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# 如何设置属性选择器表达式的值<;Func<;T、 TResult>&燃气轮机;_C#_Linq_Expression Trees - Fatal编程技术网

C# 如何设置属性选择器表达式的值<;Func<;T、 TResult>&燃气轮机;

C# 如何设置属性选择器表达式的值<;Func<;T、 TResult>&燃气轮机;,c#,linq,expression-trees,C#,Linq,Expression Trees,我需要使用模式工厂思想将Person类实体中的实体属性地址与FactoryEntities类中的表达式linq相关联,看这就是我所拥有的,我想做的: Address address = new Address(); address.Country = "Chile"; address.City = "Santiago"; address.ZipCode = "43532"; //Factory instance creation object //This is idea Person pers

我需要使用模式工厂思想将Person类实体中的实体属性地址与FactoryEntities类中的表达式linq相关联,看这就是我所拥有的,我想做的:

Address address = new Address();
address.Country = "Chile";
address.City = "Santiago";
address.ZipCode = "43532";
//Factory instance creation object
//This is idea
Person person = new FactoryEntity<Person>().AssociateWithEntity(p=>p.Address, address);

public class Person: Entity
{
    public string Name{ get; set; }
    public string LastName{ get; set; }
    public Address Address{ get; set; }
}

public class Address: Entity
{
    public string Country{ get; set; }
    public string City{ get; set; }
    public string ZipCode{ get; set; }
}

public class FactoryEntity<TEntity> where TEntity : Entity
{
    public void AssociateWithEntity<TProperty>(Expression<Func<TEntity, TProperty>> entityExpression, TProperty newValueEntity) where TProperty : Entity
    {
        if (instanceEntity == null || instanceEntity.IsTransient())
            throw new ArgumentNullException();

        /*TODO: Logic the association and validation 
        How set the newValueEntity into the property of entityExpression (x=>x.Direccion = direccion*/
    }
}
地址=新地址();
地址:Country=“智利”;
地址:City=“圣地亚哥”;
address.ZipCode=“43532”;
//工厂实例创建对象
//这就是我的想法
Person=新工厂实体()。与实体关联(p=>p.Address,Address);
公共类人员:实体
{
公共字符串名称{get;set;}
公共字符串LastName{get;set;}
公共广播地址{get;set;}
}
公共类地址:实体
{
公共字符串国家{get;set;}
公共字符串City{get;set;}
公共字符串ZipCode{get;set;}
}
公共类FactoryEntity,其中tenty:Entity
{
public void关联实体(Expression entityExpression,TProperty newValueEntity),其中TProperty:Entity
{
if(instanceEntity==null | | instanceEntity.IsTransient())
抛出新ArgumentNullException();
/*TODO:逻辑关联和验证
如何将newValueEntity设置为entityExpression(x=>x.Direccion=Direccion)的属性*/
}
}

您可以这样设置属性:

public void AssociateWithEntity<TProperty>(
    Expression<Func<TEntity, TProperty>> entityExpression,
    TProperty newValueEntity)
    where TProperty : Entity
{
    if (instanceEntity == null)
        throw new ArgumentNullException();

    var memberExpression = (MemberExpression)entityExpression.Body;
    var property = (PropertyInfo)memberExpression.Member;

    property.SetValue(instanceEntity, newValueEntity, null);
}
var factory = new FactoryEntity<Person>();
factory.AssociateWithEntity(p => p.Address, address);
Person person = factory.InstanceEntity;
另一个选项是流畅的界面:

Person person = new FactoryEntity<Person>()
    .AssociateWithEntity(p => p.Address, address)
    .InstanceEntity;
Person=新工厂实体()
.AssociateWithEntity(p=>p.地址,地址)
.实例实体;
这项工作: 下面的helper方法将getter表达式转换为setter委托

//
///将getter的lambda表达式转换为setter
/// 
公共静态操作GetSetter(表达式)
{
var memberExpression=(memberExpression)expression.Body;
var property=(PropertyInfo)memberExpression.Member;
var setMethod=property.GetSetMethod();
var parameterT=表达式参数(typeof(T),“x”);
var parameterTProperty=Expression.Parameter(typeof(TProperty),“y”);
新表达式=
Lambda(
调用(parameterT、setMethod、parameterTProperty),
参数,
参数属性
);
返回newExpression.Compile();
}

这就是我的想法,考虑到svick的贡献,我用这段代码为自己工作:

public class FactoryEntity<TEntity> where TEntity : Entity, new()

{

private TEntity _Entity;

    public FactoryEntity()
    {
        _Entity = new TEntity();
    }

public TEntity Build()
    {
        if (_Entity.IsValid())
            throw new Exception("_Entity.Id");

        return _Entity;
    }

public FactoryEntity<TEntity> AssociateWithEntity<TProperty>(Expression<Func<TEntity, TProperty>> foreignEntity, TProperty instanceEntity) where TProperty : Entity
    {
        if (instanceEntity == null || instanceEntity.IsTransient())
            throw new ArgumentNullException();

        SetObjectValue<TEntity, TProperty>(_Entity, foreignEntity, instanceEntity);
        return this;
    }

private void SetObjectValue<T, TResult>(object target, Expression<Func<T, TResult>> expression, TResult value)
    {
        var memberExpression = (MemberExpression)expression.Body;
        var propertyInfo = (PropertyInfo)memberExpression.Member;
        var newValue = Convert.ChangeType(value, value.GetType());
        propertyInfo.SetValue(target, newValue, null);
    }
}
公共类FactoryEntity,其中tenty:Entity,new()
{
私营实体;
公共工厂实体()
{
_实体=新的张力();
}
公共帐篷建设()
{
if(_Entity.IsValid())
抛出新异常(“_Entity.Id”);
返回实体;
}
public FactoryEntity Associated with Entity(表达式foreignEntity,tpProperty instanceEntity),其中tpProperty:Entity
{
if(instanceEntity==null | | instanceEntity.IsTransient())
抛出新ArgumentNullException();
SetObjectValue(_实体、foreignEntity、instanceEntity);
归还这个;
}
私有void SetObjectValue(对象目标、表达式、TResult值)
{
var memberExpression=(memberExpression)expression.Body;
var propertyInfo=(propertyInfo)memberExpression.Member;
var newValue=Convert.ChangeType(value,value.GetType());
propertyInfo.SetValue(target,newValue,null);
}
}
在这里,我调用工厂以在有效的

Person person = new FactoryEntity<Person>().AssociateWithEntity(p=>p.Address, address).Build();
Person-Person=new-FactoryEntity().AssociateWithEntity(p=>p.Address,Address).Build();
但我不知道这段代码是否最优,至少我没有调用compile()方法,你在说什么


感谢

另一个解决方案是让属性所有者ant使用反射调用属性设置器。此解决方案的优点是它不使用扩展方法,可以用任何类型调用

private void SetPropertyValue(Expression<Func<object, object>> lambda, object value)
{
    var memberExpression = (MemberExpression)lambda.Body;
    var propertyInfo = (PropertyInfo)memberExpression.Member;
    var propertyOwnerExpression = (MemberExpression)memberExpression.Expression;
    var propertyOwner = Expression.Lambda(propertyOwnerExpression).Compile().DynamicInvoke();
   
    propertyInfo.SetValue(propertyOwner, value, null);            
}
...
SetPropertyValue(s => myStuff.MyPropy, newValue);
private void SetPropertyValue(表达式lambda,对象值)
{
var memberExpression=(memberExpression)lambda.Body;
var propertyInfo=(propertyInfo)memberExpression.Member;
var propertyOwnerExpression=(MemberExpression)MemberExpression.Expression;
var propertyOwner=Expression.Lambda(propertyOwnerExpression.Compile().DynamicInvoke();
propertyInfo.SetValue(propertyOwner,value,null);
}
...
SetPropertyValue(s=>myStuff.MyPropy,newValue);
我已经制作了混合溶液和


这是我的解决方案,它使用
表达式.Assign
,但仔细看后,公认的答案也一样好

// optionally or additionally put in a class<T> to capture the object type once
// and then you don't have to repeat it if you have a lot of properties
public Action<T, TProperty> GetSetter<T, TProperty>(
   Expression<Func<T, TProperty>> pExpression
) {
   var parameter1 = Expression.Parameter(typeof(T));
   var parameter2 = Expression.Parameter(typeof(TProperty));

   // turning an expression body into a PropertyInfo is common enough
   // that it's a good idea to extract this to a reusable method
   var member = (MemberExpression)pExpression.Body;
   var propertyInfo = (PropertyInfo)member.Member;

   // use the PropertyInfo to make a property expression
   // for the first parameter (the object)
   var property = Expression.Property(parameter1, propertyInfo);

   // assignment expression that assigns the second parameter (value) to the property
   var assignment = Expression.Assign(property, parameter2);

   // then just build the lambda, which takes 2 parameters, and has the assignment
   // expression for its body
   var setter = Expression.Lambda<Action<T, TProperty>>(
      assignment,
      parameter1,
      parameter2
   );

   return setter.Compile();
}
//可选地或额外地放入一个类以捕获对象类型一次
//如果你有很多属性,你就不必重复了
公共行动GetSetter(
表达式
) {
var parameter1=表达式参数(typeof(T));
var parameter2=Expression.Parameter(typeof(TProperty));
//将表达式体转换为PropertyInfo已经很常见了
//将其提取到一个可重用的方法是一个好主意
var member=(MemberExpression)pExpression.Body;
var propertyInfo=(propertyInfo)member.member;
//使用PropertyInfo创建属性表达式
//对于第一个参数(对象)
var property=Expression.property(参数1,propertyInfo);
//为属性指定第二个参数(值)的赋值表达式
var赋值=Expression.Assign(属性,参数2);
//然后只需构建lambda,它接受2个参数,并具有赋值
//身体的表情
var setter=Expression.Lambda(
分配
参数1,
参数2
);
返回setter.Compile();
}
您可以做的另一件事是封装它们:

public sealed class StrongProperty<TObject, TProperty> {
   readonly PropertyInfo mPropertyInfo;

   public string Name => mPropertyInfo.Name;
   public Func<TObject, TProperty> Get { get; }
   public Action<TObject, TProperty> Set { get; }
   // maybe other useful properties

   internal StrongProperty(
      PropertyInfo pPropertyInfo,
      Func<TObject, TProperty> pGet,
      Action<TObject, TProperty> pSet
   ) {
      mPropertyInfo = pPropertyInfo;
      Get = pGet;
      Set = pSet;
   }
}
公共密封类strong属性{
只读属性信息mPropertyInfo;
公共字符串名称=>mPropertyInfo.Name;
公共函数Get{Get;}
公共操作集{get;}
SetPropertyValue(() => myStuff.MyProp, newValue);
// optionally or additionally put in a class<T> to capture the object type once
// and then you don't have to repeat it if you have a lot of properties
public Action<T, TProperty> GetSetter<T, TProperty>(
   Expression<Func<T, TProperty>> pExpression
) {
   var parameter1 = Expression.Parameter(typeof(T));
   var parameter2 = Expression.Parameter(typeof(TProperty));

   // turning an expression body into a PropertyInfo is common enough
   // that it's a good idea to extract this to a reusable method
   var member = (MemberExpression)pExpression.Body;
   var propertyInfo = (PropertyInfo)member.Member;

   // use the PropertyInfo to make a property expression
   // for the first parameter (the object)
   var property = Expression.Property(parameter1, propertyInfo);

   // assignment expression that assigns the second parameter (value) to the property
   var assignment = Expression.Assign(property, parameter2);

   // then just build the lambda, which takes 2 parameters, and has the assignment
   // expression for its body
   var setter = Expression.Lambda<Action<T, TProperty>>(
      assignment,
      parameter1,
      parameter2
   );

   return setter.Compile();
}
public sealed class StrongProperty<TObject, TProperty> {
   readonly PropertyInfo mPropertyInfo;

   public string Name => mPropertyInfo.Name;
   public Func<TObject, TProperty> Get { get; }
   public Action<TObject, TProperty> Set { get; }
   // maybe other useful properties

   internal StrongProperty(
      PropertyInfo pPropertyInfo,
      Func<TObject, TProperty> pGet,
      Action<TObject, TProperty> pSet
   ) {
      mPropertyInfo = pPropertyInfo;
      Get = pGet;
      Set = pSet;
   }
}