how to convert dynamic to list<dynamic> - c#

i have a variable swimlaneAttribute:
List<dynamic> swimlaneAttributes = new List<dynamic>();
but in a function i have a return type of dynamic
public dynamic GetSwimlaneAttribute(List<ProjectSwimlaneAttribute> swimlaneAttributeTable, Dictionary<string, string> dic)
{
dynamic swimlaneAttributes = null;
swimlaneAttributes = swimlaneAttributeTable.Select(s => new
{
ID = s.Id,
DataType = s.AttributeDataType,
IsCriticalField = s.IsCriticalField,
});
return swimlaneAttributes;
}
this will return some records from table parameter that i am passing!!
now i have to call this GetSwimlaneAttribute function, in return i will get all the required records(from a table)
but when i pass this to swimlaneAttributes it goes to catch block!!!
swimlaneAttributes = GetSwimlaneAttribute();
if i pass it this way, (i think the record count becomes 0)
//swimalneAttributes = GetSwimlaneAttribute as List<dynamic>;
So how to convert Dynamic to List
Thanks!

You're currently returning a sequence of anonymous type objects. That sequence can't be cast to a List<T> because it isn't a List<T>.
You could change the declaration to:
IEnumerable<dynamic> GetSwimlaneAttribute(...)
with no change to the body of the code - then to get a List<dynamic> just call it as:
List<dynamic> list = GetSwimlaneAttribute(...).ToList();
If you absolutely can't change the declaration, you could convert it outside the method:
IEnumerable<dynamic> sequence = GetSwimlaneAttribute(...);
List<dynamic> list = sequence.ToList();
Or call the extension method directly:
List<dynamic> list = Enumerable.ToList<dynamic>(GetSwimlaneAttirbute(...));
However, you should be aware that anonymous types don't cross assembly boundaries (without a bit of hackery). You should strongly consider creating a named type for this instead.
Additionally, your method body is a bit crufty - you declare a variable and assign it a null value, then immediately assign a different value, and then just return that value. The whole thing could be written as:
return swimlaneAttributeTable.Select(s => new
{
ID = s.Id,
DataType = s.AttributeDataType,
IsCriticalField = s.IsCriticalField,
});

How about this one?
List<dynamic> lstDynamic = new List<dynamic>();
lstDynamic.Add(GetSwimlaneAttribute());
and use lstDynamic.

why don't you try this way?
public List<dynamic> GetSwimlaneAttribute(List<ProjectSwimlaneAttribute> swimlaneAttributeTable, Dictionary<string, string> dic)
{
List<dynamic> swimlaneAttributes = new List<dynamic>(); // modified dynamic to List<dynamic>
swimlaneAttributes = swimlaneAttributeTable.Select(s => new
{
ID = s.Id,
DataType = s.AttributeDataType,
IsCriticalField = s.IsCriticalField,
});
return swimlaneAttributes;
}

Related

Create Tuple Using List of datatype of string in c#

I need to create Tuple from list of datatype in string, but did not get any solution.
Here is example of what I want to do.
string[] dataType = {"int", "float", "datetime"};
//I want to create list like this but dynamically datatype come from db.
//List<Tuple<int, string, string>> list = new List<Tuple<int, string, string>>();
List<Tuple<dataType[0],dataType[1], dataType[2]>> list = new List<Tuple<dataType[0],dataType[1], dataType[2]>>();
//Here datatype value is in string so I want to convert string to actual datatype.
Or if any alternative solution for this please guide me.
This is to extend my comments under question, and show you what I meant there.
It is not hard to create a list of Tuple dynamically from list of types in string format. For example, use reflection:
private Type InferType(string typeName)
{
switch (typeName.ToLowerInvariant())
{
case "int":
return typeof(int);
case "float":
return typeof(float);
default:
return Type.GetType($"System.{typeName}", true, true);
}
}
private object CreateListOfTupleFromTypes(string[] types)
{
var elementTypes = types.Select(InferType).ToArray();
// Get Tuple<,,>
var tupleDef = typeof(Tuple)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.First(mi => mi.Name == "Create"
&& mi.GetParameters().Count() == elementTypes.Length)
.ReturnType
.GetGenericTypeDefinition();
// Get Tuple<int, float, DateTime>
var tupleType = tupleDef.MakeGenericType(elementTypes);
// Get List<Tuple<int, float, DateTime>>
var listType = typeof(List<>).MakeGenericType(tupleType);
// Create list of tuple.
var list = Activator.CreateInstance(listType);
return list;
}
The problem is because the list is created using types only known at runtime, in your code, you can never use the list as strong typed list. i.e.List<Tuple<int, float, DateTime>>.
Of course, you could make life easier when the list is used in your code by using ITuple:
var list = new List<ITuple>();
list.Add(new Tuple<int, float, DateTime>(...);
int value1 = (int)list[0][0];
float value1 = (float)list[0][1];
DateTime value1 = (DateTime)list[0][2];
However, if you do that, then there is no point to use Tuple. You only need List<object[]>.
So, this comes back to my question, what is the list of tuple for in your code?
You could use dynamic here for your types. For example, when you read the three values from your database you could assign them without worrying about the types like so:
dynamic a = 10;
dynamic b = "Some String";
dynamic c = new DateTime(2020,4,9);
var test = new System.Tuple<dynamic,dynamic,dynamic>(a, b, c);
It would depend on what you want to do with the values later on.
To create a list of those tuples use:
var list = new List<System.Tuple<dynamic,dynamic,dynamic>>();
You can get the type of the variable, for instance a with
a.GetType().ToString();
I am not sure if you can set a variable type based on a string value, though (the second part of your question).

Dynamic Expression not working on dynamic objects

I want to dynamically apply a predicates to a list of dynamic object. My solution is working well when I use actual objects but it does not work on dynamic objects and I can't figure out what is the problem.
Note: I searched Stackoverflow none of similar questions are using list of dynamic objects.
I have a list of dynamic objects like the following code. The list contains two dynamic object that have two properties (Name,CreateDate). I used JsonConvert class to create dynamic objects :
var lst = new List<dynamic>();
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("Name", "John");
dict.Add("CreateDate", DateTime.Now);
lst.Add(JsonConvert.DeserializeObject<dynamic>(JsonConvert.SerializeObject(dict)));
dict.Clear();
dict.Add("Name", "sara");
dict.Add("CreateDate", DateTime.Now);
lst.Add(JsonConvert.DeserializeObject<dynamic>(JsonConvert.SerializeObject(dict)));
dict.Clear();
As you see lst is a list of dynamic objects and have 2 items in it.
Now I want to filter list to get the item with the name Jonh (p=> p.Name == "john")
To do this I had the following approach:
ParameterExpression pe = Expression.Parameter(typeof(object), "p");
CallSiteBinder name = Binder.GetMember(CSharpBinderFlags.None, "Name", typeof(object),
new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
var pname = Expression.Dynamic(name, typeof(object), pe);
var right = Expression.Constant("John");
Expression e2 = Expression.Equal(pname, right);
var qu = Expression.Lambda<Func<dynamic, bool>>(e2, pe);
var lst2 = lst.AsQueryable().Where(qu).ToList();// Count()==0 !
The lst2 should contain 1 item but it contains 0 items. But if I change the original list(lst) to a type that has a Name property (let's say List<Person>) it lst2 correctly have 1 item.
UPDATE:
Even when I use ExpandoObject to create dynamic objects it still won't work :
dynamic obj = new ExpandoObject();
var dictionary = (IDictionary<string, object>)obj;
dictionary.Add("Name", "John");
dictionary.Add("CreateDate", DateTime.Now);
UPDATE 2:
As pionted out in the comments ExpandoObject actually works and the problem is with SqlDataReader. Here are what I have tried (see Not working comments in the following code) :
...
List<dynamic> result = new List<dynamic>();
While(dr.Read()){
dynamic obj = new ExpandoObject();
var dictionary = (IDictionary<string, object>)obj;
dictionary.Add("Name","John"); // <= this works fine
// dictionary.Add("Name",dr["Name"]); // <= Not working
// dictionary.Add("Name",dr["Name"].ToItsType()); // <= Not working
// dictionary.Add("Name",dr["Name"].ToString()); // <= Not working
dictionary.Add("CreateDate", DateTime.Now);
result.Add(obj);
}
...
I was able to reproduce the issue (after your UPDATE 2 which gave me the idea) by changing the ExpandoObject example code
dictionary.Add("Name", "John");
to
dictionary.Add("Name", new string("John".ToCharArray()));
to avoid constant string interning, which lead us to the issue in the dynamic expression code.
The dynamic expression type is object, hence Expression.Equal resolves to object operator ==, i.e. ReferenceEquals. That's why the example is working with constant strings and not with runtime created strings.
What you need here is to use actual property type. So simply cast (Expression.Convert) the result of the dynamic property accessor to the expected type:
var pname = Expression.Convert(Expression.Dynamic(name, typeof(object), pe), typeof(string));
Now the expressions which refer to pname expression will resolve with the correct type (in this particular case, Equal will resolve to the overloaded string == operator which correctly compares strings by value. Same for value types like int, DateTime etc.).
dynamic obj = new ExpandoObject();
dictionary.Add("Name", "John");
dictionary.Add("CreateDate", DateTime.Now);
try the above code. Conversion is not required and ExpandoObject should allow to add or remove dynamic objects.
Why not just use dynamic objects instead of dictionary.
Following code works like charm:
var lst = new List<dynamic>();
dynamic obj = new ExpandoObject();
obj.Name = "John";
obj.CreateDate = DateTime.Now;
lst.Add(obj);
obj = new ExpandoObject(); // re-instantiate the obj if you want to differentiate from the List itself
obj.Name = "Sara";
obj.CreateDate = DateTime.Now.AddMonths(-10);
lst.Add(obj);
foreach (var item in lst)
{
Console.WriteLine($"{item.Name} - {item.CreateDate}");
}
You can even filter the list dynamically
Console.WriteLine(lst.Find(i=>i.Name == "John").Name);
Hope it helps.
EDIT
You need to re-instantiate your dynamic obj on each adding. If you dont, your list will have nothing but 2 "Sara"s.
Update
Well, with a little bit work on this this solution got worked for me.
I used JsonConvert.DeserializeObject<ExpandoObject>(...) instead of dynamic. Then wrote a LookUp method for inspecting the element. I think first problem with your code is deserializing your serialized object as dynamic instead of ExpandoObject. After that correction, it was not that hard for the casting dictinaries and getting key-value oriented values.
Here is my code:
var lst = new List<dynamic>();
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("Name", "John");
dict.Add("CreateDate", DateTime.Now);
lst.Add(JsonConvert.DeserializeObject<ExpandoObject>(JsonConvert.SerializeObject(dict)));
dict.Clear();
dict.Add("Name", "Sara");
dict.Add("CreateDate", DateTime.Now);
lst.Add(JsonConvert.DeserializeObject<ExpandoObject>(JsonConvert.SerializeObject(dict)));
dict.Clear();
var res = LookUp(lst, "Name", "Sara");
And after that LookUp method
public static object LookUp(List<dynamic> lst, string propName, object value)
{
return lst.FindAll(i =>
{
var dic = i as IDictionary<string, object>;
return dic.Keys.Any(key => dic[key].ToString().Contains(value.ToString()));
});
}
Also if you dont want to cast it to dictionary here is an alternative method for it:
private static object GetProperty(dynamic target, string name)
{
var site =
CallSite<Func<CallSite, dynamic, object>>
.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None, name, target.GetType(),
new[] {CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)}));
return site.Target(site, target);
}
public static object LookUpAlt(List<dynamic> lst, string propName, object value)
{
return lst.FindAll(i => GetProperty(i, propName).Equals(value));
}

How to create specific list type whose parameter is known at runtime and then loop through this list?

I know I can create an object whose type is known only at run time like this:
Type t = record.GetType();
var src = Activator.CreateInstance(t.BaseType);
How can I do something like List<Record>=new List<Record>() at run time?
Suppose I am getting Child Record list using Reflection like this
var ChildRecorList=src.GetType().GetProperty(propName).GetValue(src, null);
and how can then I loop through this using foreach or for loop because foreach only works for known type list. It does now work with var types. Is there way to cast Reflection value to cast at specific type whose value is known at runtime(mentioned in point 1)
You can try this to create generic type in runtime:
Type genericListType = typeof (List<>);
// if you have more than one generic argumens
// you can add your types here like typeof(MyClass),typeof(MyClass2)
Type[] genericArguments = { typeof (Record) };
// create your generic type with generic arguments
Type myGenericType = genericListType.MakeGenericType(genericArguments);
// and then you can create your instance
var recordList = Activator.CreateInstance(myGenericType);
// get your property value
recordList = src.GetType().GetProperty(propName).GetValue(src, null);
And I guess you sure your type is a List then when you creating your instance you can make a cast like this:
var recordList = (IList)Activator.CreateInstance(myGenericType);
Then you can loop through your list
foreach (var item in recordList)
{
...
}
I'm not sure If you're looking for something like this, But you can use List Inside another List or Dictionary, Also, You can store the base value with any type and get the type whenever needed, I recommend using Dictionary so that way you can name your lists:
Dictionary<String, List<Object>> Data = new Dictionary<String, List<Object>>();
Data["MyUser"] = new List<Object>();
Data["MyUser"].Add(MyDBObject);
var obj = Data["MyUser"].Find(x => x.MyKey == "MyKeyObject");
var t = obj.GetType();
var dta = (MyDBObject)obj;
foreach (var db in Data)
{
if (db.Key == "MyUser")
db.Value.Find(x => x.Name == "MyName");
}
Or If you're looking for Creating lists on runtime:
List<List<Object>> Data = new List<List<Object>>();
var mydb = Data.Count;
Data.Add(new List<Object>());
Data[mydb].Add(MyOBJ);
foreach (var db in Data)
{
if (db.Contains(MyOBJ)
return db;
}
Why don't you just use generics? You could do something like this:
public void DoSomething<T>(T type)
{
var list = new List<T>();
}
This will allow you to create a list from whichever type is passed in at runtime.

C# Determine the type of a generic list

I have a C# method that I need to pass various lists into. The type of lists will be different very often. The method itself is in a different dll and cannot know the class objects contained in the lists (no references, no using statements). The method needs to read each of the members of each of the items in a list and build and return a string based off of that.
My question is how can get the metadata for for these various objects at compiletime / runtime? Will reflection do that?
Also, once I get the metadata, how do i use it to actually use the variables?
Thank you
EDIT: currently I am using it like the following:
public string GetData(List<User> list){
//...
List<RowData> rows = new List<RowData>();
foreach (User item in list)
{
RowData row = new RowData();
row.id = count++;
row.cell = new string[3];
row.cell[0] = item.ID.ToString();
row.cell[1] = item.name;
row.cell[2] = item.age.ToString();
rows.Add(row);
}
//...
return new JavaScriptSerializer().Serialize(rows.ToArray());
Right now this is very specific. I want to replace this with generics so I can pass items other than "User"
If the parameter (will call it list for discussion's sake) coming into the method is List<T> then you can do the following:
Type type = list.GetType().GetGenericArguments()[0];
If you just have a generic T class, then you can always just go with this:
Type typeParameterType = typeof(T);
.GetType() will get you a Type and you can get a lot of descriptions about the type.
You can also discover members of the instances you have using reflection
Please be precise with what you want more exactly ?
EDIT : Here is a way, try making it an extenstion method it would be better
public static List<RowData> ToDataTable<T>(IEnumerable<T> source)
{
System.Reflection.PropertyInfo[] properties = typeof(T).GetProperties();
List<RowData> rows = new List<JQGridRow>();
foreach (var item in source)
{
RowData row = new RowData();
row.cells = new string[properties.Length];
int i=0;
foreach (var prop in properties)
{
row.cells[i] = prop.GetValue(item, null);i++;
}
rows.Add(row);
}
return rows;
}
Yes, you can use reflection to obtain the type of an object at runtime.
Simple call to object.GetType() will give you the type of this instance.
What you do with this information is up to you.
Maybe something like this?
public string GetData<T>(IEnumerable<T> list, Func<T, RowData> fillRow)
{
List<RowData> rows = new List<JQGridRow>();
foreach (User item in list)
{
RowData row = new RowData();
row.id = count++;
fillRow(row);
rows.Add(row);
}
//...
return new JavaScriptSerializer().Serialize(rows.ToArray());
}
And use it like
string s = GetData(users, row =>
{
row.cell = new string[3];
row.cell[0] = item.ID.ToString();
row.cell[1] = item.name;
row.cell[2] = item.age.ToString();
});
This might work if you treat them all as objects, using the intrinsic ToString() method for your string building.

How to retrieve Object from arraylist in c#

How to retrieve Object and its member from arraylist in c#.
You mean like this?
ArrayList list = new ArrayList();
YourObject myObject = new YourObject();
list.Add(myObject);
YourObject obj = (YourObject)list[0];
To loop through:
foreach(object o in list)
{
YourObject myObject = (YourObject)o;
.......
}
Information on ArrayList
object[] anArray = arrayListObject.ToArray();
for(int i = 0; i < anArray.Length; i++)
Console.WriteLine(((MyType)anArray[i]).PropertyName); // cast type MyType onto object instance, then retrieve attribute
Here's an example of a simple ArrayList being populated with a new KeyValuePair object. I then pull the object back out of the ArrayList, cast it back to its original type and access it property.
var testObject = new KeyValuePair<string, string>("test", "property");
var list = new ArrayList();
list.Add(testObject);
var fetch = (KeyValuePair<string, string>)list[0];
var endValue = fetch.Value;
You should use generic collections for this. Use the generic ArrayList so you dont have to cast the object when you are trying to get it out of the array.
You can also use extension methods:
ArrayList list = new ArrayList();
// If all objects in the list are of the same type
IEnumerable<MyObject> myenumerator = list.Cast<MyObject>();
// Only get objects of a certain type, ignoring others
IEnumerable<MyObject> myenumerator = list.OfType<MyObject>();
Or if you're not using a newer version of .Net, check the object type and cast using is/as
list[0] is MyObject; // returns true if it's an MyObject
list[0] as MyObject; // returns the MyObject if it's a MyObject, or null if it's something else
Edit: But if you're using a newer version of .Net...
I strongly suggest you use the Generic collections in System.Collections.Generic
var list = new List<MyObject>(); // The list is constructed to work on types of MyObject
MyObject obj = list[0];
list.Add(new AnotherObject()); // Compilation fail; AnotherObject is not MyObject
Do a type casting like this:
yourObject = new object[]{"something",123,1.2};
((System.Collections.ArrayList)yourObject)[0];

Categories