How to get the field name to check if field should include quotes or not? - c#

I need to add quotes to some fields. The field type should not considered because some strings should have quotes and others not.
So I added the following configuration:
var config = new CsvConfiguration(CultureInfo.InvariantCulture) {
ShouldQuote = args =>
{
var b = quoted.Contains(args.Field);
return b;
}
};
The quoted variable is a list of field names that need quotes.
But args.Field is not the field name but the field value. Is there a way to check what the field name is at this stage or maybe there is another way to achieve this?

You can use args.Row.HeaderRecord along with args.Row.Index to determine the header name of the field. If you also want the actual header name quoted, you will have to check args.field since the HeaderRecord will not have been populated at that point.
void Main()
{
var quoted = new List<string> { "Id" };
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
ShouldQuote = args =>
{
if (args.Row.HeaderRecord != null)
{
return quoted.Contains(args.Row.HeaderRecord[args.Row.Index]);
}
if (args.Row.Row == 1)
{
return quoted.Contains(args.Field);
}
return false;
}
};
var records = new List<Foo>{
new Foo { Id = 1, Name = "Name1" },
new Foo { Id = 2, Name = "Name2" }
};
using (var csv = new CsvWriter(Console.Out, config))
{
csv.WriteRecords(records);
}
}
// Define other methods and classes here
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}

Related

How can i add a property to object during the a run time at C#?

I have two different lists. I want to combine these list in an object. I don't know the property names in these lists, which is why I cannot create a class in advance.
public class exampleConfigProperty
{
public string PropertName { get; set; };
public string PropertValue { get; set; };
}
public class exampleFile
{
public string config1 { get; set; };
}
List<exampleConfigProperty> myList = new List<exampleConfigProperty>();
myList.add(new exampleConfigProperty {
PropertName = "Config_Property_Name",
PropertValue = "Config Property Value"
});
List<exampleFile> myListTwo = new List<exampleFile>();
myListTwo.add(new exampleFile {
config1 = "Config Value"
});
I tried to figure out if is there any way I can use the code below:
var obj = new object();
foreach(var item in myList)
{
obj.addProperty(item.PropertName, item.PropertValue );
}
foreach(var item in myListTwo)
{
obj.addProperty(nameof(item.config1), item.config1 );
}
In conclusion I try to create an object instance by using two lists,
for example:
var resut = new {
Config_Property_Name = "Config Property Value",
config1 ="Config Value"
}
dynamic type does not work so what should I do to get an object instance by using two lists?
Since you just want to make a JSON I think would fit your criteria:
var test = new Dictionary<string, string>(); //<string, object> for mixed types of values
test["key1"] = "value1";
test["key2"] = "value2";
var result = JsonConvert.SerializeObject(test); //indented for readability of result
// result:
// {
// "key1": "value1",
// "key2": "value2"
// }

Creating an anonymous object who must have the dot in Key name and put it inside another anonymous object

I'm making a JSON body for an elasticsearch query.
I have this dynamic:
var hlBodyText = new
{
bodyText = new { }
};
But there's a case in which the name must be bodyText.exact = new { }, but obviously I'm not allowed to do it and return the error message:
Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access.
There's a way to make that value name with the dot char?
EDIT
Furthermore, I have to put this object inside another object, like this:
var fieldsInner = new
{
hlBodyText.bodyText
};
What could be the best way to get this result but with the property name set with the dot?
EDIT #2
I created a class with all my parameters beacause I thought the JsonProperty attribute could help me.
internal class ElasticSearchHighlightsModel
{
[JsonProperty("bodyText")]
public object bodyText { get; set; }
[JsonProperty("title")]
public object title { get; set; }
[JsonProperty("shortDescription")]
public object shortDescription { get; set; }
[JsonProperty("bodyText.exact")]
public object bodyTextExact { get; set; }
[JsonProperty("title.exact")]
public object titleExact { get; set; }
[JsonProperty("shortDescription.exact")]
public object shortDescriptionExact { get; set; }
}
then in my method i have a condition for which I have to use some params or others.
// ...some code...
else
{
var hlBodyText = new ElasticSearchHighlightsModel() { bodyTextExact = new { } };
var hlTitle = new ElasticSearchHighlightsModel() { titleExact = new { } };
var hlShortDescription = new ElasticSearchHighlightsModel() { shortDescriptionExact = new { } };
var fieldsInner = new
{
hlBodyText.bodyTextExact,
hlTitle.titleExact,
hlShortDescription.shortDescriptionExact,
};
var fieldsContainer = new
{
pre_tags = preTags,
post_tags = postTags,
fields = fieldsInner,
};
return fieldsContainer;
}
But the fieldsInner object have the parameter names (bodyTextExact, titleExact etc...), not the JsonProperty attribute ones.
It seems this you are looking for,later u convert dictionary to json
Dictionary<string,object> obj=new Dictionary<string,object>();
obj["bodyText.exact"]=new object{};
Solved using Dictionary, then passed it inside an anonymous type obj:
IDictionary highlitsFieldsContainer = new Dictionary<string, object>();
// ... some code
highlitsFieldsContainer["bodyText.exact"] = new { };
highlitsFieldsContainer["title.exact"] = new { };
var fieldsContainer = new
{
fields = highlitsFieldsContainer,
};
// OUTPUT: fieldsContainer = { fields = { bodyText.exact = {}, title.exact = {} } }
And used a RouteValueDictionary class to read that values when elasticsearch send his response.
RouteValueDictionary _res = new RouteValueDictionary(dynamicResponse.highlights);
if (_res["shortDescription.exact"] != null)
{
// ...
}
You seem to be creating an anonymous type (not "dynamic") and wanting to serialize it with a different name that is not valid in C#. To do that you'll need to use a named type and use the JsonProperty
attribute:
internal class HlBodyText
{
[JsonProperty("bodyText.exact")]
public DateTime bodyText { get; set; }
}
and create an instance of it:
var hlBodyText = new HlBodyText()
{
bodyText = new { }
};

Insert values in class without explicit writing them

I have some huge classes and don't want to write them all out for testing, because it's a huge effort and I could forget some values what makes the test invalid.
Messages = new List<Request.Notif.NotifRuleMessages>
{
new Request.Notif.NotifRuleMessages
{
Code = 1234,
Message = new List<Request.Notif.NotifRuleMessagesMessage>
{
new Request.Notif.NotifMessagesMessage
{
Status = new Request.Notif.NotifMessagesMessageStatus
{
Code = 1,
Bool = true,
Test1 = "Test",
Test2 = "Test"
},
Rules = new List<Request.Notif.NotifMessagesMessageRule>
{
new Request.Notif.NotifMessagesMessageRule
{
Lengths = new Request.Notif.NotifMessagesMessageRuleLength
{
Lenght = 1,
Lengths = new List<Request.Notif.NotifMessagesMessageRuleLengthLength>
{
new Request.Notif.NotifMessagesMessageRuleLengthLength
{
Type = "Test",
Value = 1
}
}
},
Status = new List<Request.Notif.NotifMessagesMessageRuleStatus>
{
new Request.Notif.NotifMessagesMessageRuleStatus
{
Test1 = "Test",
Test2 = "Test"
Is there a way to automaticly fill all int values with 1 or 0 and all string values with Test and especially all objects with the right class without unit testing and external libs?
Using reflection you could populate your objects recursively and set whatever default values you choose. A small example of a helper function that could do that for you:
void SetDefaults(object testObj)
{
var props = testObj.GetType().GetProperties();
foreach (var prop in props)
{
if (prop.GetSetMethod() == null)
{
continue;
}
var propType = prop.PropertyType;
if (propType == typeof(int))
{
prop.SetValue(testObj, 1);
}
else if (propType == typeof(bool))
{
prop.SetValue(testObj, false);
}
// More conditions...
else
{
var ctor = propType.GetConstructor(Type.EmptyTypes);
var propertyObject = ctor.Invoke(new object[0]);
SetDefaults(propertyObject);
prop.SetValue(testObj, propertyObject);
}
}
}
As you can see, if your tree of objects use types that don't have default constructors (parameterless constructors) you need some more complicated logic in the else-condition. Basically the stuff going on here is a very simplified version of what happens in a dependency injection framework.
To use it, do something like:
void Main()
{
TestObject obj = new TestObject();
SetDefaults(obj);
Console.WriteLine(obj);
}
class TestObject {
public int MyInt { get; set; }
public SubTestObject SubObj { get; set; }
}
class SubTestObject {
public int MyOwnInt { get; set; }
public bool MyBoolGetter => 1 > 0;
}

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.

Select an attribute from object in a List inside another List

Can I perform a select using ternary operator to get an attribute from object inside a list?
Here is my model:
public class Xpto
{
public List<Son> Sons { get; set; }
}
public class Son
{
public string Names { get; set; }
}
And here i would like to get "Name" attribute for each son that i have:
var result = (from a in mylist
select new
{
sonsNames = a.Sons == null : <What should i put here?>
}).ToList<object>();
I've tried Sons.ToString() but it prints an object reference.
I would like to have a string list in "sonsNames" and each name separeted by a ','. Example: sonsName: 'george, john'.
what about this ?
//set up a collection
var xptos = new List<Xpto>()
{ new Xpto()
{ Sons = new List<Son>
{ new Son() { Names = "test1" },
new Son() { Names = "test2" }
}
},
new Xpto()
{
Sons = new List<Son> {
new Son() { Names = "test3" }
}
}};
//select the names
var names = xptos.SelectMany(r => r.Sons).Where(k => k.Names != null)
.Select(r => r.Names + ",") .ToList();
names.ForEach(n => Console.WriteLine(n));
Here's more info on SelectMany()

Categories