I am trying to modify the code below:
public static string ToCsv<T>(this IEnumerable<T> list, List<string> keyIndicators, List<string> inTreatmentCohort)
{
var type = typeof(T);
var props = type.GetProperties();
//Setup expression constants
var param = Expression.Parameter(type, "x");
var doublequote = Expression.Constant("\"");
var doublequoteescape = Expression.Constant("\"\"");
var comma = Expression.Constant(",");
//Convert all properties to strings, escape and enclose in double quotes
var propq = (from prop in props
let tostringcall = Expression.Call(Expression.Property(param, prop),
prop.ReflectedType.GetMethod("ToString", new Type[0]))
let replacecall = Expression.Call(tostringcall,
typeof(string).GetMethod("Replace", new[] {typeof(string), typeof(string)}), doublequote,
doublequoteescape)
select Expression.Call(
typeof(string).GetMethod("Concat", new[] {typeof(string), typeof(string), typeof(string)}),
doublequote, replacecall, doublequote)
).ToArray();
var concatLine = propq[0];
for (var i = 1; i < propq.Length; i++)
concatLine =
Expression.Call(
typeof(string).GetMethod("Concat", new[] {typeof(string), typeof(string), typeof(string)}),
concatLine, comma, propq[i]);
var method = Expression.Lambda<Func<T, string>>(concatLine, param).Compile();
var header = string.Join(",", props.Select(p => p.Name).ToArray());
return header + Environment.NewLine + string.Join(Environment.NewLine, list.Select(method).ToArray());
}
I need to filter based on the two lists (keyIndicators and inTreatmentCohort) which contain the suffix and prefix of the PropertyInfo Name field contained in the list being converted to CSV.
I tried adding a where keyIndicators.Contains(prop.Name) essentially simulating an IN statement this returns null.
I also tried putting the propq query in a foreach loop this brought the correct data but all the column names shown rather than just the column names that are selected in the keyIndicators or inTreatmentCohort list.
How do I modify this code to only return a csv that contains the columns in the two filtering lists rather than all the columns in list being converted?
Revised to include new linq queries
Have revised the code that I previously provided the Contains is now working as intended, these changes can be seen below:
public static string ToCsv<T>(this IEnumerable<T> list, List<string> keyIndicators,
List<string> inTreatmentCohorts)
{
var type = typeof(T);
var props = type.GetProperties();
//Setup expression constants
var param = Expression.Parameter(type, "x");
var doublequote = Expression.Constant("\"");
var doublequoteescape = Expression.Constant("\"\"");
var comma = Expression.Constant(",");
MethodCallExpression[] propq = { };
var propqList = new List<MethodCallExpression>();
//Convert all properties to strings, escape and enclose in double quotes
foreach (var keyIndicator in keyIndicators)
{
if (keyIndicator != "Pend" && keyIndicator != "Area" && keyIndicator != "DrugGroup" &&
keyIndicator != "Gender") continue;
propq = (from prop in props
let tostringcall = Expression.Call(Expression.Property(param, prop),
prop.ReflectedType.GetMethod("ToString", new Type[0]))
let replacecall = Expression.Call(tostringcall,
typeof(string).GetMethod("Replace", new[] { typeof(string), typeof(string) }), doublequote,
doublequoteescape)
where prop.Name.Contains(keyIndicator)
select Expression.Call(
typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string), typeof(string) }),
doublequote, replacecall, doublequote)
).ToArray();
propqList.AddRange(propq);
}
foreach (var keyIndicator in keyIndicators)
{
foreach (var inTreatmentCohort in inTreatmentCohorts)
{
propq = (from prop in props
let tostringcall = Expression.Call(Expression.Property(param, prop),
prop.ReflectedType.GetMethod("ToString", new Type[0]))
let replacecall = Expression.Call(tostringcall,
typeof(string).GetMethod("Replace", new[] { typeof(string), typeof(string) }),
doublequote,
doublequoteescape)
where prop.Name.Contains(inTreatmentCohort) && prop.Name.Contains(keyIndicator)
select Expression.Call(
typeof(string).GetMethod("Concat",
new[] { typeof(string), typeof(string), typeof(string) }),
doublequote, replacecall, doublequote)
).ToArray();
}
propqList.AddRange(propq);
}
propq = propqList.ToArray();
var concatLine = propq[0];
for (var i = 1; i < propq.Length; i++)
concatLine =
Expression.Call(
typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string), typeof(string) }),
concatLine, comma, propq[i]);
var method = Expression.Lambda<Func<T, string>>(concatLine, param).Compile();
var header = string.Join(",", props.Select(p => p.Name).ToArray());
return header + Environment.NewLine + string.Join(Environment.NewLine, list.Select(method).ToArray());
}
I need to rewrite the LINQ query for var header so that only columns selected in propq are shown when the csv is generated.
After making some revisions I managed to get the Contains to work in conjunction with a couple of foreach loops for processing the two filter lists.
the complete code is shown below:
public static string ToCsv<T>(this IEnumerable<T> list, List<string> keyIndicators,
List<string> inTreatmentCohorts)
{
var type = typeof(T);
var props = type.GetProperties();
//Setup expression constants
var param = Expression.Parameter(type, "x");
var doublequote = Expression.Constant("\"");
var doublequoteescape = Expression.Constant("\"\"");
var comma = Expression.Constant(",");
MethodCallExpression[] propq = { };
var propqList = new List<MethodCallExpression>();
var columnNames = new List<string>();
//Convert all properties to strings, escape and enclose in double quotes
foreach (var keyIndicator in keyIndicators)
{
foreach (var inTreatmentCohort in inTreatmentCohorts)
{
propq = (from prop in props
let tostringcall = Expression.Call(Expression.Property(param, prop),
prop.ReflectedType.GetMethod("ToString", new Type[0]))
let replacecall = Expression.Call(tostringcall,
typeof(string).GetMethod("Replace", new[] {typeof(string), typeof(string)}), doublequote,
doublequoteescape)
where prop.Name.Contains(keyIndicator) && prop.Name.Contains(inTreatmentCohort)
select Expression.Call(
typeof(string).GetMethod("Concat", new[] {typeof(string), typeof(string), typeof(string)}),
doublequote, replacecall, doublequote)
).ToArray();
var columnNameQuery = (from prop in props
where prop.Name.Contains(keyIndicator) && prop.Name.Contains(inTreatmentCohort)
select prop.Name);
columnNames.AddRange(columnNameQuery);
propqList.AddRange(propq);
}
}
propq = propqList.ToArray();
var concatLine = propq[0];
for (var i = 1; i < propq.Length; i++)
concatLine =
Expression.Call(
typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string), typeof(string) }),
concatLine, comma, propq[i]);
var method = Expression.Lambda<Func<T, string>>(concatLine, param).Compile();
var header = string.Join(",", columnNames.ToArray());
return header + Environment.NewLine + string.Join(Environment.NewLine, list.Select(method).ToArray());
}
The column names that I want to be included in the CSV are added to a columnNames list and are then added to the header variable so the the columns and the data match up in the CSV.