I have a simple for loop but I want to convert it to Linq and return empty Dict. if object is null. I have not used it before. Can anyone help me out on this ?
private Dictionary<string, class1> getInfo(IEnumerable<class2> infos)
{
Dictionary<string, class1> trs = new();
if (infos is null)
return trs;
//This loop I want to convert to linq
for(class2 info in infos)
{
class1 tr = new()
{
bi = info.bi,
state = bi.State,
res = Enum.value;
};
trs.Add(info.value1, tr);
}
return trs;
}
You can use .ToDictionary() to create a dictionary from IEnumerable<class2>
Dictionary<string, class1> trs = infos
?.ToDictionary(key => Key.value1,
value => new class1() {
bi = value.bi,
state = bi.State,
res = Enum.value
}) ?? new Dictionary<string, class1>();
Free Advice : I highly recommend you to use proper naming conventions while declaring class and variables, this will make your code more readable and easy to understand
Related
This question already has an answer here:
How to store multiple items in IDictionary?
(1 answer)
Closed 6 years ago.
I have created this IDictionary:
IDictionary<string, string> trace = new Dictionary<string, string>();
my goal is use it for save the content of json deserialized. I save the content in the IDictionary like this:
var obj = JsonConvert.DeserializeObject<List<RootObject>>(responseText);
foreach (var item in obj)
{
trace["date"] = item.trace.details.date;
trace["type"] = item.trace.details.type;
}
now in the obj variable I have 180 elements, the foreach over all items available in obj. The problem is that in the trace dictionary for each iteration each item is replaced, so I get only the item of the last iteration. How can I save all items in the dictionary? A dictionary shouldn't push each item automatically in the next iteration, instead of replacing it?
As #Santosh pointed out, this is expected behavior. You could instead use a List<Dictionary<String,String>>
var traces = new List<Dictionary<string, string>>();
var obj = JsonConvert.DeserializeObject<List<RootObject>>(responseText);
foreach (var item in obj)
{
var trace = new Dictionary<String,String>();
trace["date"] = item.trace.details.date;
trace["type"] = item.trace.details.type;
...
traces.Add(trace);
}
Try:
IDictionary<string, string> trace = new Dictionary<string, IList<string>>();
trace.Add("date", new List<string>())
trace.Add("type", new List<string>())
var obj = JsonConvert.DeserializeObject<List<RootObject>>(responseText);
foreach (var item in obj)
{
trace["date"].Add(item.trace.details.date)
trace["type"].Add(item.trace.details.type)
}
Plz, feel free to improve this design.
This is not how dictionaries work in C#. As the name suggests it should be one key with one value. You don't have repeated entries in dictionaries, right?
What you're probably trying to do is add to values in each entry, so I'll suggest using Tuple, since I don't know the type of your json parsed data, I'll assume string for everything, but type really won't change anything here :
var list = new List<Tuple<string,string>>();
foreach (var item in obj)
{
list.Add(new Tuple<string, string>(item.trace.details.date, item.trace.details.type));
}
Now you'll reach each entry as list[i].Item1 for a date on a given i index and list[i].Item2 for a type on the same index.
Using LINQ, you can do this:
var obj = JsonConvert.DeserializeObject<List<RootObject>>(responseText);
var traces = obj.Select(item => new Dictionary<string, string> {
{ "date", item.trace.details.date },
{ "type", item.trace.details.type }
});
You will get an IEnumerable<Dictionary<string, string>>. There isn't really a simpler way to do what you ask other than to use a collection of dictionaries.
Perhaps you can use a Lookup<string, string>, this is a one-to-many dictionary. You can create one using ToLookup() extension method:
var dates = obj.Select(o => new { Key = "date", Value = o.trace.details.date });
var types = obj.Select(o => new { Key = "type", Value = o.trace.details.type });
var lookUp = dates.Concat(types).ToLookup(kv => kv.Key, kv => kv.Value);
I have a JSON like this one:
{
"name" : "MyCustomName",
"my_node" : {
"name" : "my_node_name"
},
"dict1":"value1",
"dict2":"value2",
"dict3":"value3",
...
}
and an object:
class Node{
string value;
}
class Sample:IDictionary<string, string>{
Node node;
string name;
}
Node and Name in Sample class are always present.
The thing is I don't know how many "dictN" fields will be... and that's the point.
And the question is:
How to Deserialize that JSON to this Object?
Edit: apparently even with field names harmonized, your deserializer just can't cope with specific fields combined with general dictionary fields.
In which case, I'd just advise deserializing as a Dictionary<string, object> and building with the result:
var d = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json);
Sample s = new Sample();
s.name = (string)d["name"];
Node n = new Node();
n.value = (string)((Dictionary<string, object>)d["my_node"])["name"];
foreach (var key in d.Keys.Except(new string[] { "name", "my_node" }))
{
s.Add(key, (string)d[key]);
}
INITIAL IDEA
The following is a dictionary serializer. It has one special case of not accepting empty string.
private void SerializePerinatalModel<T>(IDictionary<string, object> dataModel, T perinatalModel)
{
Type sourceType = typeof(T);
foreach (PropertyInfo propInfo in (sourceType.GetProperties()))
{
if (dataModel.ContainsKey(propInfo.Name))
{
// if an empty string has been returned don't change the value
if (dataModel[propInfo.Name].ToNullSafeString() != String.Empty)
{
try
{
Type localType = propInfo.PropertyType;
localType = Nullable.GetUnderlyingType(localType) ?? localType;
propInfo.SetValue(perinatalModel, Convert.ChangeType(dataModel[propInfo.Name], localType), null);
}
catch (Exception e)
{
// ToDo: log update value errors
}
}
}
}
}
but could be made null safe. It does deal with nullable types.
As JSON is essentially a dictionary type then iterating through the top level types should get you there.
This is written in haste so is only a sketch of an idea.
BETTER IDEA
Also try using
foreach (var item in JsonData.Where(m => m.Key.Substring(0,4) == "dict"))
{
// add item to collection
}
might also do the biz.
You can simply have the output in the form of Dictionary<string, object>, try this piece of code instead.
System.Web.Script.Serialization.JavaScriptSerializer s =
new System.Web.Script.Serialization.JavaScriptSerializer();
var nodes = s.Deserialize<Dictionary<string, object>>(jsonString);
var dictNodes = nodes.Where(w => w.Key.StartsWith("dict"));
I have this dictionary and tuples set up in SetValue() as below :-
var myDict = new Dictionary<string, Tuple<string, string>>();
private void SetValue()
{
var myTuple1= Tuple.Create("ABC", "123");
var myTuple2= Tuple.Create("DEF", "456");
myDict.Add("One", myTuple1)
myDict.Add("Two", myTuple2)
}
I am trying to retrive the tuple in GetValue() as below :-
private void GetValue()
{
var myTuple = new Tuple<string, string>("",""); //Is this correct way to initialize tuple
if (myDict.TryGetValue(sdsId, out myTuple))
{
var x = myTuple.Item1;
var y = myTuple.Item2;
}
}
My question is whether this is the correct way to initialize tuple while retrieving the same from a dictionary ? Is there a better code?
var myTuple = new Tuple<string, string>("","");
If it's an out parameter, the object doesn't need to be initialized before being used. You should just be able to do:
Tuple<string,string> myTuple;
if (myDict.TryGetValue(sdsId, out myTuple))
{
var x = myTuple.Item1;
var y = myTuple.Item2;
}
You don't need to create an instance for an out parameter. Just declare the local variable as Tuple but don't assign a value.
Tuple<string, string> myTyple;
Foo is a class with a lot of string fields. I want to create a method Wizardify that performs an operation on many of the fields of the object. I could do it like this:
Foo Wizardify(Foo input)
{
Foo result;
result.field1 = Bar(input.field1);
result.field2 = Bar(input.field2);
result.field3 = Bar(input.field3);
...
This is some easily generated code, but I prefer not to waste fifty lines on this. Is there a way to go over selected fields of an object? Note that there are four or five fields I want to work on in a different way and they should be excluded from the iteration.
try
foreach ( FieldInfo FI in input.GetType().GetFields () )
{
FI.GetValue (input)
FI.SetValue (input, someValue)
}
Though I would not recommend the reflection approach for known Types - it is slow and depending on your specific scenario could pose some permission issue at runtime...
This is what I have - it gives me a list (names) of all properties in my classes, that later I can work on with Reflection or "Expression trees":
private static string xPrev = "";
private static List<string> result;
private static List<string> GetContentPropertiesInternal(Type t)
{
System.Reflection.PropertyInfo[] pi = t.GetProperties();
foreach (System.Reflection.PropertyInfo p in pi)
{
string propertyName = string.Join(".", new string[] { xPrev, p.Name });
if (!propertyName.Contains("Parent"))
{
Type propertyType = p.PropertyType;
if (!propertyType.ToString().StartsWith("MyCms"))
{
result.Add(string.Join(".", new string[] { xPrev, p.Name }).TrimStart(new char[] { '.' }));
}
else
{
xPrev = string.Join(".", new string[] { xPrev, p.Name });
GetContentPropertiesInternal(propertyType);
}
}
}
xPrev = "";
return result;
}
public static List<string> GetContentProperties(object o)
{
result = new List<string>();
xPrev = "";
result = GetContentPropertiesInternal(o.GetType());
return result;
}
Usage: List<string> myProperties = GetContentProperties(myObject);
Loop through typeof(YourType).GetProperties() and call GetValue or SetValue.
Note that reflection is rather slow.
You could use the Dynamic Language Runtime to generate a lambda of the type Func. You'll just need to generate the lambda once (you can cache it away) and there'll be no reflection performance hit.
Im trying to use DynamicObject in c#, and I needed an array of dynamic:
var d = new dynamic[];
which works fine.
EDIT : See ExpandoObject below.
But I also like to fill that array with some data with this compressed initialize new syntax:
var d = new dynamic[] {
new {
Name = "Some",
Number = 1010
},
new {
Name = "Other",
Number = 2010
}
}
But in that case all objects gets the non-dynamic type "object" and a loop through the items will give me an exception:
foreach (dynamic item in d)
{
#item.Name
#item.Number
}
Error : 'object' does not contain a definition for 'Name'. I guess I just initialize the array items the wrong way. How to add dynamic objects instead?
EDIT: New content:
I realize "dynamic" does not have the capability to dynamically add properties.
I better be using ExpandoObject which exposes all items in an an internal dictionary as properties. But unfortunately ExpandoObject does not seem to support this nice compressed create syntax, and the compiler complains:
var d = new ExpandoObject[]{
new ExpandoObject(){
Name="Nnn",
Number=1080
}
}
So the answer might just be : it's not possible.
Hopefully you do not really need dynamics
class Program
{
static void Main(string[] args)
{
var d = new[]
{
new
{
Name = "Some",
Number = 1010
},
new
{
Name = "Other",
Number = 2010
}
};
foreach (var item in d)
{
string s = #item.Name;
int n = #item.Number;
Console.WriteLine("{0} {1}", s, n);
}
}
}
I come a bit late but here is what i found about it :
if I can't initialise an ExpandoObject, how about initialising it with a dynamic type ?
so i did the following extension method
public static ExpandoObject CreateExpando(this object item)
{
var dictionary = new ExpandoObject() as IDictionary<string, object>;
foreach (var propertyInfo in item.GetType().GetProperties())
{
dictionary.Add(propertyInfo.Name, propertyInfo.GetValue(item, null));
}
return (ExpandoObject)dictionary;
}
I know it's far from ideal, but it's the best I could achieve for now, it works like this :
var myExpandoObject = new { Name="Alex", Age=30}.CreateExpando();
The open source framework Impromptu-Interface has a compressed initialization syntax that works with ExpandoObject.
dynamic #new = Builder.New<ExpandoObject>();
var d = #new.List(
#new.Expando(
Name:"Some",
Number: 1010
),
#new.Expando(
Name:"Other",
Number: 2010
)
);