How to loop through List<dynamic> - c#

I have a Class which contains a dynamic List, which I manage to access like this.
foreach (var c in objects)
{
foreach (dynamic i in c.data)
{
var ss = i;
}
}
The Class
public class iUpdateGrid
{
public int type { get; set; }
public string session { get; set; }
public string latitude { get; set; }
public string longitude { get; set; }
public string ip { get; set; }
public int id { get; set; }
public string station { get; set; }
public List<iGridData> h_33 { get; set; }
}
public class iGridData
{
public string table { get; set; }
public List<dynamic> data { get; set; }
}
"ss" contains now a list of objects, however have no idea how to get these values to a Dictionary or list.
One note I also need to adjust the key names.
Things I tried to do:
foreach (KeyValuePair<string, string> kv in i)
{
string key = kv.Key;
string value = kv.Value;
}
foreach statement cannot operate on variables of type 'System.Collections.IEnumerable' because 'System.Collections.IEnumerable' does not contain a public definition for 'GetEnumerator'
Also the Dynamic objects does not give me the options to access the key and/or value.
Any help how I can loop through this would be very welcome.
also when I put this on runtime "i" says its a System.Collections.Generic.Dictionary however can access this also.
Solution:
Made little chance to solution as provided, but this worked for me:
foreach (var c in objects)
{
foreach (dynamic i in c.data)
{
foreach (var v in (i as IDictionary<string, object>))
{
string key = v.Key;
object value = v.Value;
}
}
}

foreach (var v in (i as IEnumerable<object>))
{
if (v is KeyValuePair<string, string>)
{
// Do stuff
}
else if (v is List<string>)
{
//Do stuff
}
else throw new InvalidOperationException();
}

foreach (var c in objects)
{
foreach (dynamic i in c.data)
{
var property_value = i.GetType().GetProperty("PROPERTY_NAME").GetValue(i);
}
}

Related

C# foreach loop thru collection of unknown type

I have a generic method that can be called with 2 different object types, TypeA or TypeB. TypeA and TypeB are essentially identical classes except in name only. I am trying to determine how to prevent from having to duplicate the Foreach loop code for each object type. Is this possible ? thanks.
public class TypeA
{
public string Name { get; set; }
public string Department { get; set; }
public string Total { get; set; }
}
public class TypeB
{
public string Name { get; set; }
public string Department { get; set; }
public string Total { get; set; }
}
private CsvExport GenerateExport<T>(IEnumerable<T> scores)
{
CsvExport export = new CsvExport();
List<TypeA> aList = null;
List<TypeB> bList = null;
Type type = scores.GetType();
if (type.FullName.Contains("TypeA"))
{
aList = scores as List<ObjectaModel>;
}
else if (type.FullName.Contains("TypeB"))
{
bList = scores as List<ObjectbModel>;
}
foreach (var dt in aList)
{
export.AddRow();
export["Name"] = dt.Name;
export["Department"] = dt.Department;
export["Total "] = dt.Total;
};
return export;
}
In this particular case I strongly suggest you delegate the hard work to the CsvHelper library which you can also obtain from Nuget and is used like this...
public void ExportToCsv<T>(string filename, ImmutableArray<T> objects)
{
using (var writer = File.CreateText(filename))
{
var csv = new CsvWriter(writer);
csv.WriteRecords(objects);
}
}
The more general answer to your question is that you must either have both classes inherit from a common class or interface or you would have to use reflection to look for an obtain the values of the named properties.
Using a common interface...
public interface IScore
{
int HiScore {get;}
}
public class ScrabbleScore : IScore
{
public int HiScore {get;set;}
}
public class PacManScore : IScore
{
public int HiScore {get;set;}
}
public void Export<T>(IEnumerable<T> scores) where T: IScore
{
foreach(var s in scores)
{
CvsExport["Hi score"]= s.HiScore;
}
}
Using reflection...
var CsvExport = new Dictionary<string,string>();
foreach(var o in scores)
{
//note that checking the type for each object enables you to have heterogenous lists if you want
var objectType= o.GetType();
foreach(var p in objectType.GetProperties())
{
var propertyName = p.Name;
CsvExport[propertyName] = p.GetValue(o).ToString();
}
}
I would treat the reflection solution as the least favoured of the three.

Expression Bodied fields (read-only) in structs does not get copied using Reflection

I am trying to implement object deep/shallow cloning service using Reflection.
Using the function Clone<T> Simple class is being copied with all the required fields, but in case of SimpleStruct Computed field does not get copied.
What is the difference between struct and class when defining read-only fields, and how this can be solved ?
Thanks in advance.
public T Clone<T>(T source)
{
var obj = Activator.CreateInstance<T>();
var type = source.GetType();
foreach (var property in type.GetProperties())
{
if (!property.IsValid())
continue;
if (property.SetMethod != null)
{
property.SetValue(obj, property.GetValue(source));
}
}
foreach (var field in type.GetFields())
{
if (field.IsPublic == false || !field.IsValid())
continue;
field.SetValue(obj, field.GetValue(source));
}
return obj;
}
public struct SimpleStruct
{
public int I;
public string S { get; set; }
[Cloneable(CloningMode.Ignore)]
public string Ignored { get; set; }
public string Computed => S + I;
public SimpleStruct(int i, string s)
{
I = i;
S = s;
Ignored = null;
}
}
public class Simple
{
public int I;
public string S { get; set; }
[Cloneable(CloningMode.Ignore)]
public string Ignored { get; set; }
[Cloneable(CloningMode.Shallow)]
public object Shallow { get; set; }
public string Computed => S + I + Shallow;
}

C# Get field value by attribute (PropertyInfo)

I have the following class properties:
[EffectAspect(Enums.Effects.Low)]
public int Wind { set; get; }
[EffectAspect(Enums.Effects.Low)]
public int Fire { set; get; }
[EffectAspect(Enums.Effects.Medium)]
public int Water { get; set; }
[EffectAspect(Enums.Effects.Huge)]
public int Earth { get; set; }`
Now, let's say I want to calculate the total Lows, Mediums and Huges.
So I wrote something like:
List<Enums.Effects> result = new List<Enums.Effects>();
PropertyInfo[] properties = GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
object[] attrs = p.GetCustomAttributes(true);
foreach (Object attr in attrs)
{
var effectAttr = attr as EffectAspect;
if (effectAttr != null)
{
int amount = (int)p.GetConstantValue();
for (int i = 0; i < amount; i++)
{
result.Add(effectAttr.Aspect);
}
}
}
}
return result;
For example: if Wind = 3, there would be at least 3 Enums.Effects.Low inside the result list.
[AttributeUsage(AttributeTargets.Property)]
public sealed class EffectAspectAttribute : Attribute
{
public Enums.EffectsAspect { get; private set; }
public EffectAspectAttribute (Enums.EffectsAspect aspect)
{
this.Aspect = aspect;
}
}
The problems is: int amount = (int)p.GetConstantValue(); throws exceptions says:
Literal value was not found.
And I couldn't find what it means.
You can try to use
p.GetValue(this, null)
instead of
p.GetConstantValue();
You can refer this link thread: Difference between GetValue, GetConstantValue and GetRawConstantValue

Add to a collection of unknown type using reflection in c#

So I am using reflection to loop through the properties of one object and populating the values on a different object with properties of the same name. This works great but the problem comes when the property type is a collection. I want to be able to loop through each of the objects in the source collection and populate the same list with objects in the source collection.
public class SourceMessage
{
public string Name { get; set; }
public int Version { get; set; }
public IList<ValueDefinition> Values { get; set; }
}
public class ValueDefinition
{
public string Name { get; set; }
public string Value { get; set; }
}
public class TargetObject
{
public TargetObject()
{
Values = new List<TargetValueDefinition>();
}
public string Name { get; set; }
public int Version { get; set; }
public IList<TargetValueDefinition> Values { get; set; }
}
public class TargetValueDefinition
{
public string Name { get; set; }
public string Value { get; set; }
}
Then I use Reflection to populate the target from the source.
public static void PopulateFromMessage<T, TS>(ref T targetEntity, TS message)
{
var sourceType = typeof(TS);
var targetType = typeof(T);
foreach (var targetPropInfo in targetType.GetProperties())
{
if (sourceType.GetProperty(targetPropInfo.Name) != null)
{
var obj = sourceType.GetProperty(targetPropInfo.Name);
if (obj.PropertyType.Namespace == "System.Collections.Generic")
{
//var x = targetType.GetProperty(targetPropInfo.Name);
//PopulateFromMessage(ref x, sourceType.GetProperty(targetPropInfo.Name));
continue;
}
targetPropInfo.SetValue(targetEntity, sourceType.GetProperty(targetPropInfo.Name).GetValue(message), null);
}
}
}
So calling this would be like this:
private void DenormalizeMessage(SourceMessage message)
{
var newTargetObject = new TargetObject();
PopulateFromMessage(ref newTargetObject , message);
}
I can identify when the property is a collection but am uncertain of how to create new TargetValueDefinitions and populate them with the values from ValueDefinitions. In the end it is pretty much a copy of the SourceMessage in the form of a TargetObject.
This all stems from receiving messages and transforming them into objects with the same property names.
If your problem is iterating through items contained inside a single property when it is a collection, then the key would be to read the property value into a dynamic variable and not an object variable that is by default, this way you could use a foreach for it.
dynamic propVal = inputProperty.GetValue(item);
foreach (var subItem in propVal)
{
//do your stuff
}
Disclaimer: This is extremely unsafe to do and makes a lot of assumptions but it should puth you on the right path.
Change you method to this:
public static void PopulateFromMessage<T, TS>(T targetEntity, TS message)
{
var sourceType = typeof (TS);
var targetType = typeof (T);
foreach (var targetPropInfo in targetType.GetProperties())
{
if (targetPropInfo.PropertyType.IsGenericType)
{
if (targetPropInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>))
{
var originalList = sourceType.GetProperty(targetPropInfo.Name).GetValue(message) as IList;
if (originalList != null)
{
var argumentType = targetPropInfo.PropertyType.GetGenericArguments();
var listType = typeof (List<>);
var concreteType = listType.MakeGenericType(argumentType);
var newList = Activator.CreateInstance(concreteType) as IList;
foreach (var original in originalList)
{
var targetValue = Activator.CreateInstance(argumentType[0]);
// do this yourself. Here we're converting ValueDefinition to TargetValueDefinition
// targetValue.Fill(original);
}
targetPropInfo.SetValue(targetEntity, newList);
}
}
}
else
{
if (sourceType.GetProperty(targetPropInfo.Name) != null)
{
var obj = sourceType.GetProperty(targetPropInfo.Name);
if (obj.PropertyType.Namespace == "System.Collections.Generic")
{
//var x = targetType.GetProperty(targetPropInfo.Name);
//PopulateFromMessage(ref x, sourceType.GetProperty(targetPropInfo.Name));
continue;
}
targetPropInfo.SetValue(targetEntity, sourceType.GetProperty(targetPropInfo.Name).GetValue(message), null);
}
}
}
}
You should create a interface for each class (implement the methods and properties on interface) and implement it in each class. After, in function PopulateFromMessage should specify the interface allowed in method, with this you can use directly the properties of class with T and TS generic types.

How can i use generic list with foreach?

if i compiled below codes error return foreach loop how can i solve it?
Error:Error 1 foreach statement cannot operate on variables of type 'Sortlist.MyCalısan' because 'Sortlist.MyCalısan' does not contain a public definition for 'GetEnumerator' C:\Users\yusuf.karatoprak\Desktop\ExcelToSql\TestExceltoSql\Sortlist\Program.cs 46 13 Sortlist
static void EskiMetodlaListele()
{
MyCalısan myCalısan = new MyCalısan();
Calısan calisan = new Calısan();
calisan.Ad = "ali";
calisan.SoyAd = "abdullah";
calisan.ID = 1;
myCalısan.list.Add(calisan);
foreach (Calısan item in myCalısan)
{
Console.WriteLine(item.Ad.ToString());
}
}
}
public class Calısan
{
public int ID { get; set; }
public string Ad { get; set; }
public string SoyAd { get; set; }
}
public class MyCalısan
{
public List<Calısan> list { get; set; }
public MyCalısan()
{
list = new List();
}
}
Only write foreach (Calısan item in myCalısan.list).
I recommend MyCalısan to define as Collection.
public class MyCalısan : Collection<Calısan>
{
}
You should loop on MyCalisan.list; MyCalisan is just your class, and is not enumerable itself.
a few issues need to be fixed before it will compile:
public class MyCalısan{
public List<Calısan> list { get; set; }
public MyCalısan()
{
list = new List<Calısan>();
}}
foreach (Calısan item in myCalısan.list)
{
Console.WriteLine(item.Ad.ToString());
}
You need to iterate over the collection you had defined - the list property:
myCalısan.list.Add(calısan);
foreach (Calısan item in myCalısan.list)
{
Console.WriteLine(item.Ad.ToString());
}
However, if you want to iterate over myCalısan directly, make the MyCalısan class implement IEnumerable<Calısan>.

Categories