Хочу с помощью деревьев выражений LINQ сгенерировать делегат, который будет делать конкатенацию всех строковых свойств произвольного типа:
static Func<T,string> TestConcat<T>(T obj)
{
var type=obj.GetType();
LabelTarget label = Expression.Label(typeof(string), "ResultLabel");
var param = Expression.Parameter(type);
var resultExp=Expression.Variable(typeof(string), "result");
Expression assign = Expression.Assign(resultExp, Expression.Constant(""));
foreach (var prop in type.GetProperties())
{
var member = Expression.Property(param, prop);
assign = Expression.Add(assign, member, typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string) }));
}
Console.WriteLine(assign.ToString());
var block = Expression.Block(new[] { resultExp, param }, new[] { Expression.Label(label, assign), assign });
return Expression.Lambda<Func<T,string>>(block, param).Compile();
}
Ловлю NullReferenceException, но не понимаю в чем проблема...
Подскажите, как правильно сделать?
Мне кажется, вы напихали лишнего в свой метод. У меня работает такой код:
static class ConcatEx
{
public static string ConcatProps<T>(this T obj) => ConcatPropsImpl<T>.ConcatProps(obj);
private class ConcatPropsImpl<T>
{
static ConcatPropsImpl()
{
var parameter = Expression.Parameter(typeof(T), "x");
Expression body = Expression.Constant(string.Empty, typeof(string));
var method = typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string) });
foreach (var prop in typeof(T).GetProperties())
body = Expression.Add(body, Expression.Property(parameter, prop), method);
var lambda = Expression.Lambda<Func<T, string>>(body, parameter);
ConcatProps = lambda.Compile();
}
public static readonly Func<T, string> ConcatProps;
}
}
Использовать так:
var test = new Test { A = "A", B = "B", C = "C" };
Console.WriteLine(test.ConcatProps());
Ну или, если вам нужна именно функция, а не результат ее выполнения, то берите ConcatEx.ConcatProps<Test>
Но, мне кажется, на выходе не самый эффективный метод получается (string.Concat(string.Concat(string.Concat("", x.A), x.B), x.C)
)
Наверное, лучше вызывать перегрузку string.Concat
, принимающую массив:
static class ConcatEx
{
public static string ConcatProps<T>(this T obj) => ConcatPropsImpl<T>.ConcatProps(obj);
private class ConcatPropsImpl<T>
{
static ConcatPropsImpl()
{
var parameter = Expression.Parameter(typeof(T), "x");
var method = typeof(string).GetMethod("Concat", new[] { typeof(object[]) });
var props = typeof(T).GetProperties().Select(prop => Expression.Property(parameter, prop));
var array = Expression.NewArrayInit(typeof(object), props);
var body = Expression.Call(method, array);
var lambda = Expression.Lambda<Func<T, string>>(body, parameter);
ConcatProps = lambda.Compile();
}
public static readonly Func<T, string> ConcatProps;
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
При уничтожении игрового объекта Destroy(gameobject); подвисает на секунду играПричина этому проклятая библиотека A* Pathfinding Project Выключая главный...
В моемNet Core приложении я хранил данные в классе DataService