How to use dynamic Linq with List object - c#

I have List object of type dynamic like List<dynamic> but when I try to use it with Linq then it's not working. Below is my Linq syntax
var tt = lst.Where(x => (string)x.Type == "test");
So how can I use dynamic Linq on List having type as dynamic object.
It throws an error:
'System.Collections.Generic.List<object>' does not contain a definition for 'Type'

Make sure you have declared the dynamic type correctly or is there any mismatch between the objects. I just tried the same thing and it works for me.
dynamic obj = new {
Data = "sjds"
};
dynamic obj2 = new {
Data = "sjdsf"
};
List<dynamic> dynamics = new List<dynamic>();
dynamics.Add(obj);
dynamics.Add(obj2);
var str = dynamics.Where(x => x.Data == "sjds");
If your case different than this you can share the full code to better understand the scenario.

The compiler has no way to know what your dynamic objects look like. Therefore you need to tell the compiler by casting to a type. Since you're assuming that a particular property exists on your dynamic object (Type), you can try and cast it.
List<YourType> yourList = lst as List<YourType>;
if (yourList!=null){
var filtereList = yourList.Where(x=>x.Type.Equals("test"));
}

Related

dynamic.ToString() unexpected behaviour

I'm wondering how does this code work:
dynamic dynaString = 2;
string b = dynaString.ToString();
When this one is not working:
var list = new List<dynamic>();
var liststring = new List<string>();
liststring = list.Select(x => x.ToString()).ToList();
I know I can add Cast<string> after Select statement but that does not explain that behaviour. Why does ToString() on dynamic element work different when called on dynamic variable declared in code than on dynamic variable taken from list in LINQ.
I've looked into method signature of Select and it's:
My guess is that x here is a dynamic variable, so it should behave just like dynaString, but it's not. Intellisense is suggesting me that this x.ToString() returns string:
Anyone got experience with dynamics in C# and can explain me that?
I've also tried this code:
var list = new List<dynamic>();
var liststring = new List<string>();
foreach (dynamic a in list)
{
liststring.Add(a.ToString());
}
It compiles as expected, because again the a is declared as dynamic in foreach statement.
According to dynamic type docs:
The dynamic type indicates that use of the variable and references to its members bypass compile-time type checking. Instead, these operations are resolved at run time.
Type dynamic behaves like type object in most circumstances. In particular, any non-null expression can be converted to the dynamic type. The dynamic type differs from object in that operations that contain expressions of type dynamic are not resolved or type checked by the compiler.
There is no way to infer type from usage in case type checking and/or resolution is bypassed at compile-time.
If you omit generic type parameter it will by default return dynamic type even you call ToString() method. The reason is that any non-null expression can be assigned to dynamic. As dynamic is source, it will be also the result of Select(x => x.ToString()) method call.
On the other hand you can assign dynamic object to string variable as you are calling ToString() which returns string instance.

C# Covert Type into IEnumerable of same Type?

I have some methods that execute arbitrary SQL against a database and serialize that data collection into a list of a concrete type. That data is then serialized into JSON and stored in a cell in a table. Later, I need to come back and deserialize that data back into its original collection so that it can be used.
I'm having some issues figuring out how to take a Type object and create a collection of that type in order to deserialize it. Here is how my code operates:
public async Task ExecuteWidget(Guid runGuid, string widgetName, Type type, string sql,
IEnumerable<SqlParameter> parameters)
{
var report = operationsContext.ReportRuns.FirstOrDefault(n => n.RunGuid == runGuid);
CheckReportStatus(report);
var param = parameters.ToList();
var result = edwContext.Database.SqlQuery(type, sql, param.ToArray<object>());
var query = result.GetQuery(param);
var data = await result.ToListAsync();
var widgetData = new ReportRunWidgetData()
{
ReportRunId = report?.ReportRunId ?? -1, // This should never be null.
WidgetName = widgetName,
WidgetData = new JavaScriptSerializer().Serialize(data),
Query = query
};
operationsContext.ReportRunWidgetDatas.Add(widgetData);
await operationsContext.SaveChangesAsync();
}
My fetching logic looks something like this:
public object FetchWidgetData(Guid runGuid, string widgetName, Type dataType)
{
var data = operationsContext.ReportRuns
.Include("ReportRunWidgetDatas")
.FirstOrDefault(n => n.RunGuid == runGuid)?
.ReportRunWidgetDatas.FirstOrDefault(n => n.WidgetName == widgetName)?
.WidgetData;
if (data == null) return null;
var deserialized = new JavaScriptSerializer().Deserialize(data, dataType);
return deserialized;
}
Now when the ExecuteWidget method is called, the type parameter is populated by the widget's DTO datatype. For example HeadlineWidgetDTO. However, the execute command gets the data back as a List<HeadlineWidgetDTO>. When my FetchWidgetData method is called, the dataType supplied is still HeadlineWidgetDTO, but it actually needs to be of type IEnumerable<HeadlineWidgetDTO> to deserialize properly.
Given just the type for an individual data row, how can I create a Type object that is instead a collection of that type?
This is mostly a duplicate of How to use Activator to create an instance of a generic Type and casting it back to that type?, however it's hard to tell.
Basically, if you have a type object Type theType, you need to do something like:
var listType = typeof(List<>);
var typeParams = new [] {theType};
var listOfTType = listType.MakeGenericType(typeParams);
var newListOfT = Activator.CreateInstance(listOfTType);
At that point, you have a variable of type object, but that references an object of type List<WhateverYourTypeIs>. Say, theType is typeof(int), then you will have an object of List<int>. Casting it to something usuable is a whole other question though. If you want to add something to that list, I suspect the best way would be to get a MethodInfo for the Add method and Invoke it.
I thought of another way to do this if the type has a default constructor and isn't too expensive to create. Here's a sample (creating a List<int> - but that's just the way I have it coded):
var type = typeof(int);
var dummy = Activator.CreateInstance(type);
var listOfType = new[] {dummy}.ToList();
When you are finished, the listOfType variable is typed as a List<object> but refers to a List<int>. It's mostly mostly workable - for example, you can call Add(object someObj) on it. You won't get compile type parameter type checking, but you will be able to use it.

How to cast to type of object based on the object type?

I want to avoid using the specific type (forgort how I did it before)
var obj = new List<Category>();
obj = (List<Category>)EasyCache.Instance.Item(cacheKey)
Something like: obj = (obj.GetType()???)EasyCache.Instance.Item(cacheKey)
If you don't want to repeat the type name in the assignment you can just combine the declaration and the assignment:
var obj = (List<Category>)EasyCache.Instance.Item(cacheKey)
Note that the empty List<Catgeory> you create is thrown away since you overwrite it in the next line. It seems like you create a new one just to allow the use of var in the declaration.
var and dynamic are great tools, but they should not be used to replace static type checking.
You could use
obj = (dynamic)EasyCache.Instance.Item(cacheKey);
It's not a good way, but it should work.

How to Add to an unknown List property of an object at runtime?

I have a 'Profile' object/class with an IList of 'Addresses', of which, I will only know their type [profile / addresses] at runtime via GetType() / GetProperties() etc., though I wish to .Add to this list e.g.:
var profile = session.Get<ProfileRecord>(1);
dynamic obj = new ExpandoObject();
obj = profile;
obj["Addresses"].Add(addressNew);
This does not work due to:
Cannot apply indexing with [] to an expression of type
'Test.Models.ProfileRecord'.
I've been looking at IDictionary, but have been unsuccessful in my attempts, nor even know if I should be heading down that path - so what is the correct way to go about this? This entire concept is new to me, so please don't over assume my capabilites ;) Many thanks in advance.
You could do it like this if you dont know the type of profile.
var prop = profile.GetType().GetProperty("Addresses").GetValue(profile);
prop.GetType().GetMethod("Add").Invoke(prop, new object[] {1}); // Add the Value to the list
But then you must be sure the List is already initalized.
But i think you should be able to cast your object and set the Property directly like:
if(profile.GetType == typeof (ProfileRecord))
{
var record = (ProfileRecord)profile;
if (profile.Addresses == null)
{
profile.Addresses = new List<Address>();
}
prfile.Addresses.Add(addressNew);
}

Is it possible to create an object instance based on a string value denoting its type?

I'm trying to dynamically create an object of a certain type in a LINQ-to-XML query based on a string within my XML document. I'm used to being able to dynamically create an object of any type in PHP and JavaScript by simply being able to write something like:
$obj = new $typeName();
Ideally, I'd like to be able to do something like:
List<someObj> = (from someObjs in XMLfile
select new someObj()
{
Name = (string)someObjs.Element("name"),
NestedObj = new someObjs.Element("nestedObj").Element("type")()
{
NestedName = (string)someObjs.Element("nestedObj").Element("name")
}
}).ToList();
I just can't figure out how to do it without grabbing a hold of the current executing assembly.
You can use:
Activator.CreateInstance(Type.GetType(typeName))
Of course, this only works for types with a parameterless constructor.
Update (initializing the object):
You can use C# 4 dynamic typing features to set properties of the newly created object:
dynamic newObj = Activator.CreateInstance(Type.GetType(typeName));
newObj.NestedName = str;
In the context of a LINQ to XML query, you may have to resort to lambda syntax with explicit body:
var list = XMLFile.Select(someObjs => {
dynamic nestedObj = Activator.CreateInstance(
Type.GetType(someObjs.Element("nestedObj").Element("type")));
nestedObj.NestedName = (string)someObjs.Element("nestedObj").Element("name");
return new someObj {
Name = (string)someObjs.Element("name"),
NestedObj = nestedObj
};
}).ToList();
Use the createinstance method of activator class

Categories