0

So I have a situation where I need to dynamically update properties of my object based on values contained. In the case below, I need to update the value with replacing the first two characters of the current value with a different string if condition is true.

PersonDetail.EvaluateConditionalRule("ID", 
                    "((ID.Length > Convert.ToInt32(@0) ) AND ID.Substring(Convert.ToInt32(@1), Convert.ToInt32(@2)) == @3 )",
                     new[] { "1", "0", "2", "SS" }, " ID = (@0  + ID.Substring(Convert.ToInt32(@1))) " , new[] { "98", "2" });


   public static void EvaluateConditionalRule(this PersonDetail  Detail, String PropertyToEvaluate,
            String ConditionalExpression, String[] parameters, String IfTrueExpression,String[] IfTrueExpreassionparameters  )
          {
               var property =  Detail.GetType().GetProperties().Where(x => x.Name == PropertyToEvaluate).FirstOrDefault();
               if (property == null)
                    throw new InvalidDataException(String.Format("Please specify a valid {0} property name for the evaluation.",  Detail.GetType()));
               //put together the condition like so 

               if (new[] {  Detail }.AsQueryable().Where(ConditionalExpression, parameters).Count() > 0 && IfTrueExpression != null)
               {
                    var result = new[] {  Detail }.AsQueryable().Select(IfTrueExpression, IfTrueExpreassionparameters);

                  //Stuck Here as result does not contain expected value 

                    property.SetValue( Detail,result , null);
               }
          }

Essentially what I want is, to be able to execute expressions fed this, and I don't think I have the format right for the substring replace expression to correctly evaluate. What I want from the above is something like

ID = "98"+  ID.Substring(2);

Any help will be appreciated. Thanks

Kobojunkie
  • 6,375
  • 31
  • 109
  • 164

2 Answers2

0

Not sure what exactly you mean saying "dynamically" but i suppose the approach with lambdas does not fit you:

static void Main(string[] args) {
        User user = new User { ID = 5, Name = "Test" };
        SetNewValue(user, u => u.Name, s => s.StartsWith("T"), s => s + "123");
    }

    static void SetNewValue<TObject, TProperty>(TObject obj, Func<TObject, TProperty> propertyGetter, Func<TProperty, bool> condition, Func<TProperty, TProperty> modifier) {
        TProperty property = propertyGetter(obj);
        if (condition(property)) {
            TProperty newValue = modifier(property);
            //set via reflection
        }
    }

So I would recommend you using Expression trees which allow you to build any runtime construction you like, for part of your example

var exp = Expression.Call(Expression.Constant("test"), typeof(string).GetMethod("Substring", new[] { typeof(int) }), Expression.Constant(2));            
Console.WriteLine(Expression.Lambda(exp).Compile().DynamicInvoke()); //prints "st"

However if you want to use strings with raw c# code as expressions check the CSharpCodeProvider class

Oleg Golovkov
  • 596
  • 1
  • 4
  • 18
0

Please give us some information on why you need the updates to be this dynamic. Do you want the user to enter the condition strings by hand?

About your code:

Your selector string is wrong. In the LINQ Dynamic Query Library there is a special syntax for it. Please look that up in the Documentation (see paragraph Expression Language and Data Object Initializers) provided with the sample: http://msdn.microsoft.com/en-US/vstudio/bb894665.aspx

I wrote a small sample:

var id = new string[] { "SS41231" }.AsQueryable();

// *it* represents the current element
var res = id.Where("it.Length > @0 AND it.Substring(@1, @2) = @3", 1, 0, 2, "SS"); // Save the result, don't throw it away.

if (res.Any())
{
    // Line below in normal LINQ: string newID = res.Select(x => "98" + x.Substring(2)).First();
    string newId = res.Select("@0 + it.Substring(@1)", "98", 2).Cast<string>().First();

    Console.WriteLine(newId);
}

Please write some feedback.

Greetings.

hBGl
  • 274
  • 2
  • 10