get parameter base on value of another property c# expression tree - c#

i have two class :
class JoinedMapVoucher
{
public string Code1 { get; set; }
public string Code2 { get; set; }
public string Code3 { get; set; }
public DL DL1 { get; set; }
public DL DL2 { get; set; }
public DL DL3 { get; set; }
public DL DL4 { get; set; }
}
class DL
{
public long DLTypeRef { get; set; }
}
here i have a dictionary which keys are DLTypeRefs and values are code that should not be null for example in this example if DLTypeRef is 5 then Code1 property should have value and can not be null.
what i want to do is i get code that should not be null dynamically from dictionary.
and then i want to get that Code from JoinedMapVoucher type and check if it is null or not.
in code below i write comments where i want to get Code from dictionary and then get that property from JoinedMapVoucher parameter but it not work.
var dic = new Dictionary<long, string>();
dic.Add(5, "Code1");
dic.Add(-1, "NullCode");
var dicConst = Expression.Constant(dic);
var list = Expression.Constant(new List<long> { 1, 2, 3, 4, 5 });
var defaultDL = new DL { DLTypeRef = -1, Id = -1 };
var foos = new List<JoinedMapVoucher> {new JoinedMapVoucher { DL2 = new DL { DLTypeRef = 5, Id = 55 } } }.AsQueryable();
var containsMethod = typeof(List<long>).GetMethod(nameof(List<long>.Contains), new[] { typeof(long) });
var parameter = Expression.Parameter(typeof(JoinedMapVoucher), "JoinedMapVoucher");
for (var i = 1; i <= 4; i++)
{
var dl = Expression.PropertyOrField(parameter, "DL" + i.ToString());
var actualDL = Expression.Coalesce(dl, Expression.Constant(defaultDL));
var dlTypeRef = Expression.PropertyOrField(actualDL, "DLTypeRef");
var or1 = Expression.Or(Expression.Equal(dlTypeRef, Expression.Constant((long)-1)), Expression.Not(Expression.Call(list, containsMethod, dlTypeRef)));
var dicGetItemMethod = typeof(Dictionary<long, string>).GetMethod("get_Item", new[] { typeof(long) });
var getCode = Expression.Constant(Expression.Call(dicConst, dicGetItemMethod, dlTypeRef)); **//here this call should return code from dictionary which it can be Code5 or NullCode**
**var needCode=Expression.PropertyOrFeild(parameter,getCode) // then i want to get Code property from parameter dynamically**
var lambda = Expression.Lambda<Func<JoinedMapVoucher, bool>>(or1, new ParameterExpression[] { parameter });
Console.WriteLine(lambda.Body);
foos = foos.Where(lambda);
}
how to get property dynamically in needCode variable?

You need to build a switch statement which will switch on getCode value and return corresponding property. Something along this lines:
var getCode = Expression.Call(dicConst, dicGetItemMethod, dlTypeRef);
SwitchExpression switchExpr =
Expression.Switch(
getCode,
Expression.Constant("-1"), // default case when none is matched
new SwitchCase[]
{
Expression.SwitchCase( // switch case for "Code1" returned from dict
Expression.PropertyOrField(parameter, nameof(JoinedMapVoucher.Code1)),
Expression.Constant( nameof(JoinedMapVoucher.Code1))
),
Expression.SwitchCase( // switch case for "NullCode" returned from dict
Expression.PropertyOrField(parameter, nameof(JoinedMapVoucher.Code2)),
Expression.Constant("NullCode")
),
}
);
Which should represent something along this lines generated in your lambda:
var code = dictionary[dlTypeRef];
switch (code)
{
case "Code1":
return JoinedMapVoucher.Code1;
case NullCode:
return JoinedMapVoucher.Code2;
default:
return "-1";
}

Related

C#- Filter data based on child class or using string query

Hi I have a scenario to filter the data based sub-object field please help me. From controller as query I pass Expression String.
class MasterDocument
{
private Id;
public ICollection<SubDocument> documents { get; set; }
}
class SubDocument
{
private Id;
public int Age { get; set; }
}
var filterQuery = "documents.Age == 25";
var filteredResult = MasterDocument.Where(filterQuery).ToList();
to filter the Data 
how to create Expression from string to filter data from Substructure.
Well, that's quite complicated topic, but i will first give code example and later focus on caveats:
I would follow approach and define it as another extension method:
using System.Linq.Expressions;
namespace ConsoleApp2;
public static class WhereExtensions
{
public static IEnumerable<T> Where<T>(
this IEnumerable<T> collection,
string filterExpression)
{
// Most probably you'd like to have here more sophisticated validations.
var itemsToCompare = filterExpression.Split("==")
.Select(x => x.Trim())
.ToArray();
if (itemsToCompare.Length != 2)
{
throw new InvalidOperationException();
}
var source = Expression.Parameter(typeof(T));
var property = itemsToCompare[0];
var valueToCompareAgainst = itemsToCompare[1];
var memberExpr = source.GetMemberExpression(property);
var comparisonExpr = Expression.Equal(
Expression.Call(memberExpr, typeof(object).GetMethod("ToString")),
Expression.Constant(valueToCompareAgainst)
);
var predicate = Expression.Lambda<Func<T, bool>>(comparisonExpr, source);
return collection.Where(predicate.Compile());
}
public static MemberExpression GetMemberExpression(
this ParameterExpression parameter,
string memberExpression)
{
var properties = memberExpression.Split('.');
if (!properties.Any())
{
throw new InvalidOperationException();
}
var memberExpr = Expression.PropertyOrField(parameter, properties[0]);
foreach (var property in properties.Skip(1))
{
memberExpr = Expression.PropertyOrField(memberExpr, property);
}
return memberExpr;
}
}
and the usage would be:
using ConsoleApp2;
var example = new[]
{
new TestClass() { Id = 1, Description = "a" },
new TestClass() { Id = 2, Description = "a" },
new TestClass() { Id = 3, Description = "b" },
new TestClass() { Id = 4, Description = "b" },
};
var result1 = example.Where("Id == 1").ToList();
var result2 = example.Where("Description == b").ToList();
Console.WriteLine("Items with Id == 1");
result1.ForEach(x => Console.WriteLine($"Id: {x.Id} , Descr: {x.Description}"));
Console.WriteLine("Items with Description == b");
result2.ForEach(x => Console.WriteLine($"Id: {x.Id} , Descr: {x.Description}"));
class TestClass
{
public int Id { get; set; }
public string Description { get; set; }
}
This codes returns:
NOW, THE CAVEATS
It's very tricky to cast value to compare against to an arbitrary type T, that's why i reversed the problem, and I call "ToString" on whetever member we want to compare
Expression.Call(memberExpr, typeof(object).GetMethod("ToString"))
But this also could have it's own issues, as often "ToString" returns default tpye name. But works well with integers and simple value types.

Deserialise JSON to C# array, where index is in the property name

Could anyone provide their approach for deserializing the following JSON
{
"i": 5
"b0": "ABC",
"b1": "DEF",
"b2": "GHI",
"s0": "SABC",
"s1": "SDEF",
"s2": "SGHI",
}
into a class in C# to provide the same structure as this
class Example {
public int Index {get;set;}
public string[] B {get;set;}
public string[] S {get;set;}
}
var b = new [] {"ABC", "DEF", "GHI"}
var s = new [] {"SABC", "SDEF", "SGHI"}
I generally use ServiceStack.Text, but Json.Net approach or even a BsonDocument from the MongoDb provider is fine.
Could use a JToken and use .Values() then .ToArray():
var json = "{\r\n \"b0\": \"ABC\",\r\n \"b1\": \"DEF\",\r\n \"b2\": \"GHI\",\r\n}";
var token = JToken.Parse(json);
var b = token.Values().ToArray();
This one solution might be useful too:
public class Example
{
public int Index { get; set; }
public string[] B { get; set; }
public string[] S { get; set; }
}
var strData = #"{'i': 5, 'b0': 'ABC','b1': 'DEF', 'b2': 'GHI', 's0': 'SABC', 's1': 'SDEF', 's2': 'SGHI',}";
var data = JsonConvert.DeserializeObject<JToken>(strData).Values().ToList();
Example result = new Example();
result.Index = data.Values().FirstOrDefault(x => x.Path == "i").Value<int>();
result.B = data.Values().Where(x => x.Path.StartsWith("b")).Select(x => x.Value<string>()).ToArray();
result.S = data.Values().Where(x => x.Path.StartsWith("s")).Select(x => x.Value<string>()).ToArray();
there is solution for dynamic name of arrays, but string array is not the best type in this case:
public class Example
{
public int Index { get; set; }
public Dictionary<string, string[]> Data { set; get; }
}
var s = #"{'i': 5, 'b0': 'ABC','b1': 'DEF', 'b2': 'GHI', 's0': 'SABC', 's1': 'SDEF', 's2': 'SGHI',}";
var data = JsonConvert.DeserializeObject<JToken>(s).Values().ToList();
Example result = new Example();
result.Index = data.Values().FirstOrDefault(x => x.Path == "i").Value<int>();
result.Data = new Dictionary<string, string[]>();
var stringData = data.Values().Where(x => x.Path != "i").ToList();
stringData.ForEach(x =>
{
var key = x.Path[0].ToString();
if (!result.Data.ContainsKey(key))
{
result.Data.Add(key, new string[0]);
}
var currentValue = result.Data[key].ToList();
currentValue.Add(x.Value<string>());
result.Data[key] = currentValue.ToArray();
});

Creating dynamic Expression Tree for selected search criteria

I have an Expression Tree to create a dynamic where clause based on the criteria a user selects on a checkbox.
Eg: - User wants to search for: "test"
User selects
1. Prop1
2. Prop2
for an Object
MyDBObject
The search query will look like
dbRecords.Where(r=> r.Prop1.Contains("test") || r.Prop2.Contains("test"))
The reason to use an Expression Tree is so that it can be used for any unknown number of properties of an unknown object.
I almost have it working, but I get Argument Expression is not valid
Also how does one initialize an empty boolean expression other than using
"something that evaluates to -- true/false" ?
I've only read about them for a few hours by now so maybe there's something I didn't see yet.
public static Expression<Func<T, bool>> CreatePredicateFromCrtieriaAndSearchTerm<T>(List<string> checkedCriteria, string searchTerm)
{
// sample checked records
checkedCriteria = new[]
{
new { Name = "Prop1", DisplayValue = "Checkbox value 1" },
new { Name = "Prop2", DisplayValue = "Checkbox value 2" }
}
.Select(x => x.Name).ToList();
var param = Expression.Parameter(typeof(T), "record");
Expression oneEqualsOne = Expression.Equal(Expression.Constant(1), Expression.Constant(1));
// Creates (record => (1=1) AND ...)
Expression<Func<T, bool>> finalExpression = Expression.Lambda<Func<T, bool>>(oneEqualsOne, param);
Console.WriteLine(finalExpression);
try
{
// Iterate through properties, find selected props and create
// (record.SelectedProp1.Contains("searchTerm") || record.SelectedProp2.Contains("searchTerm") ... )
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
List<Expression> matchExpressions = new List<Expression>();
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
for (int j = 0; j < checkedCriteria.Count; j++)
{
if (prop.Name == checkedCriteria[j])
{
// add to where expression
Expression left = Expression.Property(param, prop.Name);
MethodInfo contains = typeof(string).GetMethod("Contains", new[] { typeof(string) });
Expression right = Expression.Constant(searchTerm, searchTerm.GetType());
Expression matchExpression = Expression.Call(left, contains, right);
matchExpressions.Add(matchExpression);
}
}
}
// Creates (1=0 OR ... OR ...)
Expression currentPredicateBody = Expression.Equal(Expression.Constant(1), Expression.Constant(0));
foreach (var matchExpression in matchExpressions)
{
currentPredicateBody = Expression.MakeBinary(ExpressionType.OrElse, matchExpression, currentPredicateBody);
Console.WriteLine(currentPredicateBody);
}
// ( (1=0) || record.SelectedProp1.Contains("searchTerm") || record.SelectedProp2.Contains("searchTerm") )
if (matchExpressions.Count > 0)
{
oneEqualsOne = Expression.AndAlso(oneEqualsOne, currentPredicateBody);
Console.WriteLine(oneEqualsOne);
}
// Full expression:
// ( record => (1=1) AND ( (1=0) || record.SelectedProp1.Contains("searchTerm") || record.SelectedProp2.Contains("searchTerm") ))
finalExpression = Expression.Lambda<Func<T, bool>>(oneEqualsOne, new ParameterExpression[] { param });
Console.WriteLine(finalExpression);
}
catch (Exception ex)
{
throw new Exception(string.Format(#"Error occurred creating where predicate from checked criteria: {0}", ex.Message));
}
return finalExpression;
}
internal class MyDBObject
{
public int Id { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
public string Prop4 { get; set; }
public string Prop5 { get; set; }
public string Prop11 { get; set; }
public string Prop12 { get; set; }
public string Prop13 { get; set; }
public string Prop14 { get; set; }
public string Prop15 { get; set; }
public string Prop21 { get; set; }
public string Prop22 { get; set; }
public string Prop23 { get; set; }
public string Prop24 { get; set; }
public string Prop25 { get; set; }
}
public static void Main(string[] args)
{
List<MyDBObject> dbRecords = new List<MyDBObject>
{
new MyDBObject { Id = 1, Prop2 = "O1_P2", Prop3 = "O1_P3", Prop12 = "O1_P12", Prop15 = "O1_P15", Prop24 = "O1_P24", Prop25 = "O1_P25" },
new MyDBObject { Id = 2, Prop15 = "O2_P15", Prop21 = "test", Prop22 = "O2_P22", Prop23 = "O2_P23", Prop24 = "O2_P24", Prop25 = "O2_P25" },
new MyDBObject { Id = 3, Prop21 = "O3_P21", Prop22 = "O3_P22", Prop23 = "O3_P23", Prop24 = "test", Prop25 = "O3_P25" }
};
try
{
var predicate = CreatePredicateFromCrtieriaAndSearchTerm<MyDBObject>(null, "test");
var query = dbRecords.AsQueryable().Provider.CreateQuery<MyObject>(predicate);
List<MyObject> results = query.ToList();
foreach (var rs in results)
{
Console.WriteLine("Id: " + rs.Id);
}
}
catch (Exception ex)
{
Console.WriteLine("Error->> " + ex.Message);
}
}
Try this code:
public static Expression<Func<T, bool>> CreatePredicate<T>(List<string> propsToSearch,
string valueToSearch)
{
var parameter = Expression.Parameter(typeof(T), "record");
// filtering is not required
if (!propsToSearch.Any() || string.IsNullOrEmpty(valueToSearch))
return Expression.Lambda<Func<T, bool>>(Expression.Constant(true), parameter);
var props = typeof(T).GetProperties()
.Select(p => p.Name)
.Intersect(propsToSearch.Distinct());
var containsMethod = typeof(string).GetMethod("Contains");
var body = props
.Select(p => Expression.PropertyOrField(parameter, p))
.Aggregate((Expression) Expression.Constant(false),
(c, n) => Expression.OrElse(c,
Expression.Call(n, containsMethod, Expression.Constant(valueToSearch)))
);
var lambda = Expression.Lambda<Func<T, bool>>(body, parameter);
return lambda;
}
It return record => true if there is no properties to search or search patern is empty. QueryProvider can be smart enough to not generate sql where in this case.
Update: I created a demo (it's not working because of security restriction of dotNetFiddle, but localy works fine)

How to create dynamic NRules

I am getting this exception:
variable 'e' of type 'MyClass' referenced from scope '', but it is not defined
I want to create dynamic rules with nested property. When I create static rules it works fine, but not in dynamic mode. Also, I want to use expression for dynamic rules using these lines of code if possible:
PatternBuilder customerPattern = builder.LeftHandSide().Pattern(typeof(Customer), "customer");
Expression<Func<Customer, bool>> customerCondition = customer => customer.Name == "John Do";
customerPattern.Condition(customerCondition);
I tried the code below to create and execute rules dynamically, but I am getting an exception. Why?
class Program
{
static void Main(string[] args)
{
try
{
CustomRuleRepository repository = new CustomRuleRepository();
List<RuleEngineEntity> rules = new List<RuleEngineEntity>();
rules.Add(new RuleEngineEntity { FieldName = "Age", Name = "CustomerCheck", Value = 20 });
repository.LoadRules(rules);
//Compile rules
var factory = repository.Compile();
//Create a working session
var session = factory.CreateSession();
RuleEngineRequestModel ruleEngineRequestModel = new RuleEngineRequestModel { ruleList = rules, customerData = new Customer { Name = "A", Age = 24 } };
session.Insert(ruleEngineRequestModel);
var IspassedorNot = session.Fire();
}
catch (Exception e) {
Console.WriteLine(e.Message);
}
}
}
public class RuleEngineRequestModel
{
public List<RuleEngineEntity> ruleList { get; set; }
public Customer customerData { get; set; }
}
public class RuleEngineEntity
{
public string Name { get; set; }
public int Value { get; set; }
public string Operator { get; set; }
public string FieldName { get; set; }
}
public class Customer
{
public string Name { get; set; }
public int Age { get; set; }
}
public class CustomRuleRepository : IRuleRepository
{
private readonly IRuleSet _ruleSet = new RuleSet("customerRule");
public IEnumerable<IRuleSet> GetRuleSets()
{
return new[] {_ruleSet};
}
public void LoadRules(List<RuleEngineEntity> list)
{
_ruleSet.Add(
BuildRule(list)
);
}
public List<IRuleDefinition> BuildRule(List<RuleEngineEntity> list)
{
NRules.RuleModel.Builders.RuleBuilder builder = null;
List<IRuleDefinition> rulesList = new List<IRuleDefinition>();
builder = new NRules.RuleModel.Builders.RuleBuilder();
builder.Name("CustomerDetail");
ParameterExpression customerParameter = null;
LambdaExpression customerCondition = null;
PatternBuilder customerPattern = null;
try
{
var orGroup = builder.LeftHandSide().Group(GroupType.Or);
foreach (var item in list)
{
var andGroup = orGroup.Group(GroupType.And);
customerPattern = andGroup.Pattern(typeof(RuleEngineRequestModel), item.Name);
customerParameter = customerPattern.Declaration.ToParameterExpression();
customerCondition =
Expression.Lambda(
Expression.GreaterThan(CreateParameterExpression(typeof(RuleEngineRequestModel), "customerData", typeof(Customer), item.FieldName),
Expression.Constant(item.Value)), customerParameter);
customerPattern.Condition(customerCondition);
}
Expression<Action<IContext>> action =
(ctx) => Console.WriteLine("Action triggered");
builder.RightHandSide().Action(action);
rulesList.Add(builder.Build());
}
catch (Exception e)
{
}
return rulesList;
}
public Expression CreateParameterExpression(Type type, string propertyName, Type type2, string propertyName2)
{
ParameterExpression pe = Expression.Parameter(type, "e");
Expression left = Expression.Property(pe, type.GetProperty(propertyName));
return Expression.Property(left, type2.GetProperty(propertyName2));
}
}
You have a CreateParameterExpression method, that's supposed to create a property access expression. But in that method you are creating a parameter expression there with a name "e", which does not correspond to any pattern that you defined in your rule. This causes the "variable not found" exception.
You simply need one MemberExpression to access the customerData property, and then another one to access the nested property, configured in the RuleEngineEntity.
Here is an updated BuildRule method that implements the necessary expression tree.
public List<IRuleDefinition> BuildRule(List<RuleEngineEntity> list)
{
var builder = new NRules.RuleModel.Builders.RuleBuilder();
builder.Name("CustomerDetail");
var orGroup = builder.LeftHandSide().Group(GroupType.Or);
foreach (var item in list)
{
var andGroup = orGroup.Group(GroupType.And);
var modelPattern = andGroup.Pattern(typeof(RuleEngineRequestModel), item.Name);
var modelParameter = modelPattern.Declaration.ToParameterExpression();
var customerData = Expression.Property(modelParameter, nameof(RuleEngineRequestModel.customerData));
var customerCondition = Expression.Lambda(
Expression.GreaterThan(
Expression.Property(customerData, item.FieldName),
Expression.Constant(item.Value)),
modelParameter);
modelPattern.Condition(customerCondition);
}
Expression<Action<IContext>> action =
ctx => Console.WriteLine("Action triggered");
builder.RightHandSide().Action(action);
var rule = builder.Build();
return new List<IRuleDefinition> {rule};
}

Custom File Parser

I am building a parser for a custom pipe delimited file format and I am finding my code to be very bulky, could someone suggest better methods of parsing this data?
The file's data is broken down by a line delimited by a pipe (|), each line starts with a record type, followed by an ID, followed by different number of columns after.
Ex:
CDI|11111|OTHERDATA|somemore|other
CEX001|123131|DATA|data
CCC|123131|DATA|data1|data2|data3|data4|data5|data6
. I am splitting by pipe, then grabbing the first two columns, and then using a switch checking the first line and calling a function that will parse the remaining into an object purpose built for that record type. I would really like a more elegant method.
public Dictionary<string, DataRecord> Parse()
{
var data = new Dictionary<string, DataRecord>();
var rawDataDict = new Dictionary<string, List<List<string>>>();
foreach (var line in File.ReadLines(_path))
{
var split = line.Split('|');
var Id = split[1];
if (!rawDataDict.ContainsKey(Id))
{
rawDataDict.Add(Id, new List<List<string>> {split.ToList()});
}
else
{
rawDataDict[Id].Add(split.ToList());
}
}
rawDataDict.ToList().ForEach(pair =>
{
var key = pair.Key.ToString();
var values = pair.Value;
foreach (var value in values)
{
var recordType = value[0];
switch (recordType)
{
case "CDI":
var cdiRecord = ParseCdi(value);
if (!data.ContainsKey(key))
{
data.Add(key, new DataRecord
{
Id = key, CdiRecords = new List<CdiRecord>() { cdiRecord }
});
}
else
{
data[key].CdiRecords.Add(cdiRecord);
}
break;
case "CEX015":
var cexRecord = ParseCex(value);
if (!data.ContainsKey(key))
{
data.Add(key, new DataRecord
{
Id = key,
CexRecords = new List<Cex015Record>() { cexRecord }
});
}
else
{
data[key].CexRecords.Add(cexRecord);
}
break;
case "CPH":
CphRecord cphRecord = ParseCph(value);
if (!data.ContainsKey(key))
{
data.Add(key, new DataRecord
{
Id = key,
CphRecords = new List<CphRecord>() { cphRecord }
});
}
else
{
data[key].CphRecords.Add(cphRecord);
}
break;
}
}
});
return data;
}
Try out FileHelper, here is your exact example - http://www.filehelpers.net/example/QuickStart/ReadFileDelimited/
Given you're data of
CDI|11111|OTHERDATA|Datas
CEX001|123131|DATA
CCC|123131
You could create a class to model this to allow FileHelpers to parse the delimited file:
[DelimitedRecord("|")]
public class Record
{
public string Type { get; set; }
public string[] Fields { get; set; }
}
Then we could allow FileHelpers to parse in to this object type:
var engine = new FileHelperEngine<Record>();
var records = engine.ReadFile("Input.txt");
After we've got all the records loaded in to Record objects we can use a bit of linq to pull them in to their given types
var cdis = records.Where(x => x.Type == "CDI")
.Select(x => new Cdi(x.Fields[0], x.Fields[1], x.Fields[2])
.ToArray();
var cexs = records.Where(x => x.Type == "CEX001")
.Select(x => new Cex(x.Fields[0], x.Fields[1)
.ToArray();
var cccs = records.Where(x => x.Type == "CCC")
.Select(x => new Ccc(x.Fields[0])
.ToArray();
You could also simplify the above using something like AutoMapper - http://automapper.org/
Alternatively you could use ConditionalRecord attributes which will only parse certain lines if they match a given criteria. This will however be slower the more record types you have but you're code will be cleaner and FileHelpers will be doing most of the heavy lifting:
[DelimitedRecord("|")]
[ConditionalRecord(RecordCondition.IncludeIfMatchRegex, "^CDI")]
public class Cdi
{
public string Type { get; set; }
public int Number { get; set; }
public string Data1 { get; set; }
public string Data2 { get; set; }
public string Data3 { get; set; }
}
[DelimitedRecord("|")]
[ConditionalRecord(RecordCondition.IncludeIfMatchRegex, "^CEX001")]
public class Cex001
{
public string Type { get; set; }
public int Number { get; set; }
public string Data1 { get; set; }
}
[DelimitedRecord("|")]
[ConditionalRecord(RecordCondition.IncludeIfMatchRegex, "^CCC")]
public class Ccc
{
public string Type { get; set; }
public int Number { get; set; }
}
var input =
#"CDI|11111|Data1|Data2|Data3
CEX001|123131|Data1
CCC|123131";
var CdiEngine = new FileHelperEngine<Cdi>();
var cdis = CdiEngine.ReadString(input);
var cexEngine = new FileHelperEngine<Cex001>();
var cexs = cexEngine.ReadString(input);
var cccEngine = new FileHelperEngine<Ccc>();
var cccs = cccEngine.ReadString(input);
Your first loop isn't really doing anything other than organizing your data differently. You should be able to eliminate it and use the data as it is from the file. Something like this should give you what you want:
foreach (var line in File.ReadLines(_path))
{
var split = line.Split('|');
var key = split[1];
var value = split;
var recordType = value[0];
switch (recordType)
{
case "CDI":
var cdiRecord = ParseCdi(value.ToList());
if (!data.ContainsKey(key))
{
data.Add(key, new DataRecord
{
Id = key, CdiRecords = new List<CdiRecord>() { cdiRecord }
});
}
else
{
data[key].CdiRecords.Add(cdiRecord);
}
break;
case "CEX015":
var cexRecord = ParseCex(value.ToList());
if (!data.ContainsKey(key))
{
data.Add(key, new DataRecord
{
Id = key,
CexRecords = new List<Cex015Record>() { cexRecord }
});
}
else
{
data[key].CexRecords.Add(cexRecord);
}
break;
case "CPH":
CphRecord cphRecord = ParseCph(value.ToList());
if (!data.ContainsKey(key))
{
data.Add(key, new DataRecord
{
Id = key,
CphRecords = new List<CphRecord>() { cphRecord }
});
}
else
{
data[key].CphRecords.Add(cphRecord);
}
break;
}
};
Caveat: This is just put together here and hasn't been properly checked for syntax.

Categories