C# Linq, object definition does not contains a property - c#

I need your help
I just wrote the following code
var anynomousObject = new { Amount = 10, weight = 20 };
List<object> ListOfAnynomous = new List<object> { anynomousObject };
var productQuery =
from prod in ListOfAnynomous
select new { prod.Amount, prod.weight }; // here it object on 'prod.Amount, prod.weight' that the object defenetion does not contains the "Amount" and "weight" properties
foreach (var v in productQuery)
{
Console.WriteLine(v.Amount, v.weight);
}
so please could you help me to solve this problem.

You need to make a class of your object definition, or using the dynamic keywork instead of boxing in object :
var anynomousObject = new { Amount = 10, weight = 20 };
List<dynamic> ListOfAnynomous = new List<dynamic> { anynomousObject };
var productQuery =
from prod in ListOfAnynomous
select new { prod.Amount, prod.weight };
foreach (var v in productQuery)
{
Console.WriteLine(v.Amount, v.weight);
}
this is because, when you box as object, the compiler doesn't know the definition of your anonymous var. Dynamic make it evaluate at runtime instead of compile-time.
The other option is to create a class or struct.

Your List<object> has a list of objects. The Linq query looks this list, and all it sees are regular objects.
Either use a class or a structure to store your objects, or use List<dynamic>

Related

How to easily merge two anonymous objects with different data structure?

I would like to merge these two anonymous objects:
var man1 = new {
name = new {
first = "viet"
},
age = 20
};
var man2 = new {
name = new {
last = "vo"
},
address = "123 street"
};
Into a single one:
var man = new {
name = new {
first = "viet",
last = "vo"
},
age = 20,
address = "123 street"
};
I looked for a solution but found nothing clever.
Convert the anonymous object to ExpandoObject which is essentially a dictionary of string key and object value:
var man1Expando = man1.ToDynamic();
var man2Expando = man2.ToDynamic();
public static ExpandoObject ToDynamic(this object obj)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (var propertyInfo in obj.GetType().GetProperties())
{
var currentValue = propertyInfo.GetValue(obj);
if (propertyInfo.PropertyType.IsAnonymous())
{
expando.Add(propertyInfo.Name, currentValue.ToDynamic());
}
else
{
expando.Add(propertyInfo.Name, currentValue);
}
}
return expando as ExpandoObject;
}
I'm using a helper extension to establish whether a type is an anonymous one:
public static bool IsAnonymous(this Type type)
{
return type.DeclaringType is null
&& type.IsGenericType
&& type.IsSealed
&& type.IsClass
&& type.Name.Contains("Anonymous");
}
Then, merge two resulting expando objects into one, but recursively, checking for nested expando objects:
var result = MergeDictionaries(man1Expando, man2Expando, overwriteTarget: true);
public static IDictionary<string, object> MergeDictionaries(
IDictionary<string, object> targetDictionary,
IDictionary<string, object> sourceDictionary,
bool overwriteTarget)
{
foreach (var pair in sourceDictionary)
{
if (!targetDictionary.ContainsKey(pair.Key))
{
targetDictionary.Add(pair.Key, sourceDictionary[pair.Key]);
}
else
{
if (targetDictionary[pair.Key] is IDictionary<string, object> innerTargetDictionary)
{
if (pair.Value is IDictionary<string, object> innerSourceDictionary)
{
targetDictionary[pair.Key] = MergeDictionaries(
innerTargetDictionary,
innerSourceDictionary,
overwriteTarget);
}
else
{
// What to do when target propety is nested, but source is not?
// Who takes precedence? Target nested property or source value?
if (overwriteTarget)
{
// Replace target dictionary with source value.
targetDictionary[pair.Key] = pair.Value;
}
}
}
else
{
if (pair.Value is IDictionary<string, object> innerSourceDictionary)
{
// What to do when target propety is not nested, but source is?
// Who takes precedence? Target value or source nested value?
if (overwriteTarget)
{
// Replace target value with source dictionary.
targetDictionary[pair.Key] = innerSourceDictionary;
}
}
else
{
// Both target and source are not nested.
// Who takes precedence? Target value or source value?
if (overwriteTarget)
{
// Replace target value with source value.
targetDictionary[pair.Key] = pair.Value;
}
}
}
}
}
return targetDictionary;
}
The overwriteTarget parameter decides which object takes priority when merging.
Usage code:
var man1 = new
{
name = new
{
first = "viet",
},
age = 20,
};
var man2 = new
{
name = new
{
last = "vo",
},
address = "123 street",
};
var man1Expando = man1.ToDynamic();
var man2Expando = man2.ToDynamic();
dynamic result = MergeDictionaries(man1Expando, man2Expando, overwriteTarget: true);
Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented));
and the result:
{
"name": {
"first": "viet",
"last": "vo"
},
"age": 20,
"address": "123 street"
}
Notice how I assigned the result to dynamic. Leaving compiler assign the type will leave you with expando object presented as IDictionary<string, object>. With a dictionary representation, you cannot access properties in the same manner as if it was an anonymous object:
var result = MergeDictionaries(man1Expando, man2Expando, overwriteTarget: true);
result.name; // ERROR
That's why the dynamic. With dynamic you are losing compile time checking, but have two anonymous objects merged into one. You have to judge for yourself if it suits you.
There's nothing built-in in the C# language to support your use case. Thus, the question in your title needs to be answered with "Sorry, there is no easy way".
I can offer the following alternatives:
Do it manually:
var man = new {
name = new {
first = man1.name.first,
last = man2.name.first
},
age = man1.age,
address = man2.address
};
Use a class instead of an anonymous type for the resulting type (let's call it CompleteMan). Then, you can
create a new instance var man = new CompleteMan(); ,
use reflection to collect the properties and values from your "partial men" (man1 and man2),
assign those values to the properties of your man.
It's "easy" in the sense that the implementation will be fairly straight-forward, but it will still be a lot of code, and you need to take your nested types (name) into account.
If you desperately want to avoid non-anonymous types, you could probably use an empty anonymous target object, but creating this object (var man = new { name = new { first = (string)null, last = (string)null, ...) is not really less work than creating a class in the first place.
Use a dedicated dynamic data structure instead of anonymous C# classes:
The Newtonsoft JSON library supports merging of JSON objects.
Dictionaries can also be merged easily.
ExpandoObjects can be merged easily as well.

Migrate property of objects to one list object

I have collection of objects which has property with type of collection.
How can i quick migrate objects property to the one of collection object with help Linq.
Class obj
{
list<int> aa;
List<obj> b = new List<obj>()
{
new obj()
{
aa = new List<int>(){1,2,3}
},
new obj()
{
aa = new List<int>(){4,5,6}
}
}
}
i need to migrate all properties name "aa" of objects collection to one collection.
Thanks.
Use LINQ and SelectMany:
var result = b.SelectMany(o=>o.aa).ToList();

Make a List of objects using an existing list

I have a class named DataAPIKey. I have a second class which inherits from that one.
In my code I have a List, and I would like to use that to make a list of the new class. Is there any way to do this without using a for each loop?
Using the example below I made the following code which seems to be doing what I want.
List<DataAPIKey> apiList = db.GetPendingAction("Character");
List<DataCharacter> charList = apiList.Select(k => {
DataCharacter dc = new DataCharacter(k.apiKeyId, k.keyId, k.verificationCode);
return dc;
}).ToList()
Use the LINQ Select method.
var newList = oldList.Select(oldItem => new InheritedItem(oldItem)).ToList();
In plain English this translates to "Take each item from oldList, feed each as a function parameter to a function which will take that item and perform some logic to return a different type of item, then take all the returned items and populate them into a new List."
Or if you don't have a constructor to initialize the inherited class then you can provide any code block:
var newList = oldList.Select(oldItem =>
{
var newItem = new InheritedItem();
newItem.Property = oldItem.Property;
return newItem;
}).ToList();
Or an initializer:
var newList = oldList.Select(oldItem => new InheritedItem()
{
Property = oldItem.Property,
Property2 = oldItem.Property2
}).ToList();

LINQ Group By along with percent of list that contains element

Example is probably the easiest way to explain:
{1,2,2,3}
becomes
{
{1,0.25}
{2,0.5}
{3,0.25}
}
I'm thinking I'd do the inner pairs using a simple struct. I understand using GroupBy and everything, but is there a way to create a new list like this in one big LINQ statement?
another example:
{'a','g','a','a','f'}
becomes
{
{'a',0.6}
{'g',0.2}
{'f',0.2}
}
You want something like this
[TestMethod]
public void T()
{
var mySet = new List<string> { "a", "b", "a" };
var set = from i in mySet
group i by i into g
select new { Item = g.Key, Percentage = ((double)g.Count()) / mySet.Count() };
Assert.AreEqual(2, set.Count());
Assert.AreEqual("a", set.First().Item);
Assert.AreEqual(2.0/3, set.First().Percentage);
}

LINQ and creating NON anonymous return values

I think I understand returning records of an anonymous type from But in this I want to create NEW CatalogEntries, and set them from the values selected. (context is a Devart LinqConnect database context, which lets me grab a view).
My solution works, but it seems clumsy. I want to do this in one from statement.
var query = from it in context.Viewbostons
select it;
foreach (GPLContext.Viewboston item in query)
{
CatalogEntry card = new CatalogEntry();
card.idx = item.Idx;
card.product = item.Product;
card.size = (long)item.SizeBytes;
card.date = item.Date.ToString();
card.type = item.Type;
card.classification = item.Classification;
card.distributor = item.Distributor;
card.egplDate = item.EgplDate.ToString();
card.classificationVal = (int)item.ClassificationInt;
card.handling = item.Handling;
card.creator = item.Creator;
card.datum = item.Datum;
card.elevation = (int)item.ElevationFt;
card.description = item.Description;
card.dirLocation = item.DoLocation;
card.bbox = item.Bbox;
card.uniqID = item.UniqId;
values.Add(card);
}
CatalogResults response = new CatalogResults();
I just tried this:
var query2 = from item in context.Viewbostons
select new CatalogResults
{ item.Idx,
item.Product,
(long)item.SizeBytes,
item.Date.ToString(),
item.Type,
item.Classification,
item.Distributor,
item.EgplDate.ToString(),
(int)item.ClassificationInt,
item.Handling,
item.Creator,
item.Datum,
(int)item.ElevationFt,
item.Description,
item.DoLocation,
item.Bbox,
item.UniqId
};
But I get the following error:
Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a
collection initializer because it does not implement
'System.Collections.IEnumerable' C:\Users\ysg4206\Documents\Visual
Studio
2010\Projects\CatalogService\CatalogService\CatalogService.svc.cs 91 25 CatalogService
I should tell you what the definition of the CatalogResults is that I want to return:
[DataContract]
public class CatalogResults
{
CatalogEntry[] _results;
[DataMember]
public CatalogEntry[] results
{
get { return _results; }
set { _results = value; }
}
}
My mind is dull today, apologies to all. You are being helpful. The end result is going to be serialized by WCF to a JSON structure, I need the array wrapped in a object with some information about size, etc.
Since .NET 3.0 you can use object initializer like shown below:
var catalogResults = new CatalogResults
{
results = context.Viewbostons
.Select(it => new CatalogEntry
{
idx = it.Idx,
product = it.Product,
...
})
.ToArray()
};
So if this is only one place where you are using CatalogEntry property setters - make all properties read-only so CatalogEntry will be immutable.
MSDN, Object initializer:
Object initializers let you assign values to any accessible fields or properties of an
object at creation time without having to explicitly invoke a constructor.
The trick here is to create a IQueryable, and then take the FirstOrDefault() value as your response (if you want a single response) or ToArray() (if you want an array). The error you are getting (Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a collection initializer because it does not implement 'System.Collections.IEnumerable') is because you're trying to create an IEnumerable within the CatalogEntry object (by referencing the item variable).
var response = (from item in context.Viewbostons
select new CatalogEntry()
{
idx = item.Idx,
product = item.Product,
size = (long)item.SizeBytes,
...
}).ToArray();
You don't have to create anonymous types in a Linq select. You can specify your real type.
var query = context.Viewbostons.Select( it =>
new CatalogEntry
{
idx = it.idx,
... etc
});
This should work:
var query = from it in context.Viewbostons
select new CatalogEntry()
{
// ...
};

Categories