I am having trouble getting the property Names of the IEnumerable properties in my models. I cant seem to get the Nested IEnumerables from the TModel classes. I have looked into some reflection examples but haven't something quite along these lines.
I am looking to just get the IEnumerable property names for each nested model and send the property name to a list. The actual value is not important.
Any help would be greatly appreciated.
// TModel = DataContent in this context.
public class GetModelBase<TModel>
{
public string Error { get; set; }
public IEnumerable<TModel> DataContent { get; set; }
}
public class DataContent
{
public int Total { get; set; }
public IEnumerable<Data> Data { get; set; }
}
public class Data
{
public int DataId{ get; set; }
IEnumerable<DataInformation> DataInformation{ get; set; }
}
public IEnumerable<GetModelBase<TModel>> ResponseAsList<TModel>()
{
// ResponseBody in this context is a string representation of json of the models above...
var toArray = new ConvertJsonArray<GetModelBase<TModel>>(ResponseBody).ReturnJsonArray();
}
// T = GetModelBase<DataContent> in this context.
public class ConvertJsonArray<T>
{
public ConvertJsonArray(string responseString)
{
_responseString = responseString;
Convert();
}
public void Convert()
{
var result = JObject.Parse(_responseString);
// This is where I am having trouble... I am unable to get the nested IEnumerable names.
Type t = typeof(T);
PropertyInfo[] propertyInformation = t.GetProperties(BindingFlags.Public|BindingFlags.Instance);
List<string> toLists = new List<string>();
foreach (PropertyInfo pi in propertyInformation)
toLists.Add(pi.Name);
// End of Property Information Issuse...
foreach (string s in toLists.ToArray())
{
if (result[s] != null)
{
if (!(result[s] is JArray)) result[s] = new JArray(result[s]);
}
}
_jsonAsArray = result.ToString();
}
public string ReturnJsonArray()
{
return _jsonAsArray;
}
private string _responseString { get; set; }
private string _jsonAsArray { get; set; }
}
The result I am looking for in the above code sample would be a list containing only the IEnumerable names as such { "DataContent", "Data", "DataInformation" }
UPDATE:
I am still having trouble looping through each model. I have a nearly working code example.
// This replaces the Type code in the Convert method...
GetProperties(typeof(T))
private void GetProperties(Type classType)
{
foreach (PropertyInfo property in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (property.PropertyType.IsGenericType && (property.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
{
ValuesToList.Add(property.Name);
foreach (Type nestedType in property.PropertyType.GetGenericArguments())
{
GetProperties(nestedType);
}
}
}
}
private List<string> ValuesToList { get; set; }
The results for this yields { "DataContent", "Data" } but fails to get "DataInformation". For some reason the IEnumerables are not hit while in the foreach loop. Additional help would be appreciated.
You already have the PropertyInfo, so you are almost there - all that is left is to recognize which properties are of type IEnumerable<...>, where ... can be an arbitrary type.
For this purpose, check the PropertyType property.
It is a Type instance for which you can check whether it is based upon the generic type definition IEnumerable<T> by means of the GetGenericTypeDefinition method.
That method will throw an exception for non-generic types, so you will also have to check IsGenericType:
if (pi.PropertyType.IsGenericType
&& (pi.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
{
toLists.Add(pi.Name);
}
I have one model value
status.cs
public class statusModel
{
public string OrderNo { get; set; }
public string TicketNo { get; set; }
public IList<statusModel> statusModelList {get; set;}
}
I have one method
statusChangeController.cs
public class statusChangeController
{
Public JsonResult SaveStatus(statusModel statusValue)
{
....
....
}
}
I am looking to pass the IList value into the model class. I have mentioned the process below,
public ActionResult TransmitStatus(IList<statusModel> tranmittingData)
{
List<statusModel> statusToUpdate = transmittingData.statusModelList.where(x=>x.public).ToList();
statusChangeController status = new statusChangeController();
status.SaveStatus(statusToUpdate);
}
How can it be achieved. I am looking for the guidance to pass the IList as paramter to non IList value.
Thanks in advance.
You can use foreach or ForEach method
foreach (var s in statusToUpdate)
status.SaveStatus(s);
Or statusToUpdate.ForEach (x=> status.SaveStatus(x));
You can also make a method inside controller to handle list
public JsonResult SaveStatus(List<statusModel> statusValue)
{
foreach (var s in statusToUpdate)
this.SaveStatus(s);
}
If i have this class:
public class CacheClass
{
public string UserID { get; set; }
public List<string> TabId { get; set; }
public List<string> State { get; set; }
public List<string> CanAdmin { get; set; }
}
Then i add value to class and add to cache. I assign to my var type variable cache value:
var k = System.Web.HttpContext.Current.Cache[objUserInfo.UserID.ToString()];
So, how i can get foreach loop with var k and get all value?
As you will see k is an object (hover over var), since the Cache dictionary isn't strongly typed. The compiler doesn't know the actual type is CacheClass. So step 1 is to cast it. I would prefer to use as since it won't throw an exception if casting fails:
var k = System.Web.HttpContext.Current.Cache[objUserInfo.UserID.ToString()] as CacheClass;
Using as does require you to to do a null-check to make sure the cast went okay:
if (k != null)
{
foreach (string x in k.State)
{ }
}
You are probably missing the cast
var k = System.Web.HttpContext.Current.Cache[objUserInfo.UserID.ToString()] as CacheClass;
foreach(var state in k.State) {
// ...
}
I have a dictionary of strings and object that i obtained deserializing this json answer:
{"labels":[{"id":"1","descrizione":"Etichetta interna","tipo":"0","template_file":"et_int.txt"},{"id":"2","descrizione":"Etichetta esterna","tipo":"1","template_file":"et_ext.txt"}],"0":200,"error":false,"status":200}
using the code:
var labels = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json);
Now i want to loop only trought the objects inside the "labels" key.
I tried
foreach (var outer in labels["labels"]){/* code */}
but i got error:
CS1579: foreach statement cannot operate on variables of type 'object' because 'object' does not contain a public definition for 'GetEnumerator'.
Solved replacing the dictionary with a class, thank you
Create a class to deserialize your json:
To create classes, you can copy the json in clipboard and use the
Edit / Paste special / Paste JSON as class
in visual studio (I use vs2013).
[TestMethod]
public void test()
{
string json = "{\"labels\" : [{\"id\" : \"1\",\"descrizione\" : \"Etichetta interna\",\"tipo\" : \"0\",\"template_file\" : \"et_int.txt\"}, {\"id\" : \"2\",\"descrizione\" : \"Etichetta esterna\",\"tipo\" : \"1\",\"template_file\" : \"et_ext.txt\"}],\"0\" : 200,\"error\" : false,\"status\" : 200}";
var root = JsonConvert.DeserializeObject<Rootobject>(json);
foreach (var label in root.Labels)
{
//Use label.Id, label.Descrizione, label.Tipo, label.TemplateFile
}
}
public class Rootobject
{
public Label[] Labels { get; set; }
public int _0 { get; set; }
public bool Error { get; set; }
public int Status { get; set; }
}
public class Label
{
public string Id { get; set; }
public string Descrizione { get; set; }
public string Tipo { get; set; }
public string TemplateFile { get; set; }
}
You need to loop through your dictionary.
foreach(KeyValuePair<string, Object> entry in labels)
{
// do something with entry.Value or entry.Key
}
Once you start looping through it you will get access to key and value. Since you are interested to look at entry.value you can do operation on that easily. Currently your dictionary value is type of object which does not have an enumerator
Your problem is that you've defined the Type of Value for each dictionary entry as object. C# can't know how to loop over on object. So you need to work out what type is actually inside the object once the JavaScriptSerializer have parsed the JSON. One way is
var t = typeof(labels["labels"]);
Once you know what type the serializer is creating, all you need to do is cast the object back to that type. For example, assuming it's a list of objects
var labels = (List<object>)labels["labels"];
foreach (var label in labels)
{
}
Alternatively, if each object in the JSON is the same, you could try create the dictionary as the type you need. So you serializing becomes
var labels = new JavaScriptSerializer()
.Deserialize<Dictionary<string, List<object>>>(json);
A possible solution:
static void Main(string[] args) {
string json = #"{'labels':[{'id':'1','descrizione':'Etichetta interna','tipo':'0','template_file':'et_int.txt'},{'id':'2','descrizione':'Etichetta esterna','tipo':'1','template_file':'et_ext.txt'}],'0':200,'error':false,'status':200}";
var labels = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json);
IEnumerable inner_labels = labels["labels"] as IEnumerable;
if (inner_labels != null) {
foreach (var outer in inner_labels) {
Console.WriteLine(outer);
}
}
}
Otherwise, you can create a class with deserialization information and instruct the deserializer to deserialize your json string to that type:
using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using System.Xml.Serialization;
[Serializable]
public class JsonData {
[XmlElement("labels")]
public List<JsonLabel> labels { get; set; }
[XmlElement("0")]
public int zero { get; set; }
[XmlElement("error")]
public bool error { get; set; }
[XmlElement("status")]
public int status { get; set; }
}
[Serializable]
public class JsonLabel {
[XmlElement("id")]
public int id { get; set; }
[XmlElement("descrizione")]
public string descrizione { get; set; }
[XmlElement("tipo")]
public int tipo { get; set; }
[XmlElement("template_file")]
public string template_file { get; set; }
}
class Program {
static void Main(string[] args) {
string json = #"your json string here...";
var jsonData = new JavaScriptSerializer().Deserialize<JsonData>(json);
foreach (var label in jsonData.labels) {
Console.WriteLine(label.id);
}
}
}
Could you please try below snippet?
It might be help you.
foreach (var item in labels["labels"] as ArrayList)
{
Console.Write(item);
}
I have two List with a common property i need to compare both and change the final list accordingly
class ClassA
{
public string Property1 { get; set; }
public List<ClassB> LstClassB { get; set; }
}
class ClassB
{
public string PropertyToCompare { get; set; }
public string Property2 { get; set; }
}
class ClassC
{
public string Property { get; set; }
public List<ClassB> LstClassB { get; set; }
}
class ClassD : ClassA
{
public bool PropertyToChange { get; set; }
}
void fun()
{
List<ClassC> LstClassC = new List<ClassC>();
//populate LstClassC
List<ClassD> LstClassD = new List<ClassD>();
//populate LstClassD
foreach (var objectC in LstClassC)
{
foreach (var objectBFromClassC in objectC.LstClassB)
{
foreach (var objectD in LstClassD)
{
foreach (var objectBFromD in objectD.LstClassB)
{
if (objectBFromD.PropertyToCompare == objectBFromClassC.PropertyToCompare)
objectD.PropertyToChange = newValue;
}
}
}
}
}
so this is what i want to change in LINQ in a efficient way within the list since the LstD is bound to a DataGrid, so everytime i update the value for PropertyToChange based on the same condition i want it to be reflected in DataGrid
You can use SelectMany to flatten each of the two lists of lists that you have into lists of the child elements, and then you can Join those two lists together based on the common property. Using Join will be able to use a hash-based lookup to find the matching items from each collection, which will be a lot faster than looking through every single combination, as you're currently doing iteratively.
var query = from d in LstClassD
from dChild in d.LstClassB
join cChild in LstClassC.SelectMany(c => c.LstClassB)
on dChild.PropertyToCompare equals cChild.PropertyToCompare
into matches
where matches.Any()
select d;
foreach (var d in query)
d.PropertyToChange = newValue;
I can't comment on how efficient this is, however I'd use Linq's Intersects function.
If you want the below code in an interactive format go to this link https://dotnetfiddle.net/x1gIXQ
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var x = new List<String>();
x.Add("Hello");
x.Add("Hola");
x.Add("Aloha");
var y = new List<String>();
y.Add("Goodbye");
y.Add("Adios");
y.Add("Aloha");
var intersects = x.Intersect(y);
intersects.ToList().ForEach(zz=> Console.WriteLine(zz));
}
}
If you want more information about the intersects function check it out here. https://msdn.microsoft.com/en-us/library/vstudio/bb460136%28v=vs.100%29.aspx