Working with C# Anonymous Types - c#

I am calling a method that returns a List variable that contains a c# Anonymous Type objects. For example:
List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
list.Add( new {
ContactID = c.ContactID,
FullName = c.FullName
});
}
return list;
How do I reference this type properties in the code I am working on like for example
foreach ( object o in list ) {
Console.WriteLine( o.ContactID );
}
I know that my sample is not possible, I have only wrote that way to say that I need to identify each property of the anonymous type exactly.
Thanks!
Solution:
Not just one of the answer is correct and/or suggest a working solution. I have ended up to using Option 3 of Greg answer. And I learned something very interesting regarding the dynamic in .NET 4.0!

You can't return a list of an anonymous type, it will have to be a list of object. Thus you will lose the type information.
Option 1
Don't use an anonymous type. If you are trying to use an anonymous type in more than one method, then create a real class.
Option 2
Don't downcast your anonymous type to object. (must be in one method)
var list = allContacts
.Select(c => new { c.ContactID, c.FullName })
.ToList();
foreach (var o in list) {
Console.WriteLine(o.ContactID);
}
Option 3
Use the dynamic keyword. (.NET 4 required)
foreach (dynamic o in list) {
Console.WriteLine(o.ContactID);
}
Option 4
Use some dirty reflection.

foreach ( var o in list ) {
Console.WriteLine( o.ContactID );
}
this will work only if list is IEnumerable<anonymous type>, like this:
var list = allContacts.Select(c => new {
ContactID = c.ContactID,
FullName = c.FullName
});
}
but you can't return anonymous types, because you must define return type (you can't return var) and anonymous types can't have names. you should create non-anonymous type if you with to pass it. Actually anonymous types should not be used too much, except for inside of queries.

If you have a method like this:
List<object> GetContactInfo() {
List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
list.Add( new {
ContactID = c.ContactID,
FullName = c.FullName
});
}
return list;
}
You shouldn't really do this, but there's a very ugly and not future-proof technique that you can use:
static T CastByExample<T>(object target, T example) {
return (T)target;
}
// .....
var example = new { ContactID = 0, FullName = "" };
foreach (var o in GetContactInfo()) {
var c = CastByExample(o, example);
Console.WriteLine(c.ContactID);
}
It relies on the fact (which can change!) that the compiler reuses anonymous types for types that have the same "shape" (properties names and types). Since your "example" matches the "shape" of the type in the method, the same type is reused.
Dynamic variables in C# 4 are the best way to solve this though.

You cannot do this with anonymous types. Just create a Contact class/struct and use that.
List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
list.Add( c );
}
Then you can do this:
foreach ( var o in list ) {
Console.WriteLine( o.ContactID );
}
...or this:
foreach ( object o in list ) {
Console.WriteLine( ((Contact)o).ContactID ); //Gives intellisense
}
Of course you should in that case just do create a Contact list instead of an object list:
List<Contact> list = new List<Contact>();
foreach ( Contact c in allContacts ) {
list.Add( c );
}
EDIT: Missed essential part of the question. Now fixed.
EDIT: Changed answer yet again. See above.

replacing object with var in for each construct may work

I know I'm late to the party but I researching somthing else and found this article which answers your question.
It is possible to cast the list of objects back into the anonymous type.
public static void Main()
{
foreach (object item in GetList())
{
var x = Cast(item, new { ContactID = 0, FullName = "" });
Console.WriteLine(x.ContactID + " " + x.FullName);
}
}
public static IEnumerable<object> GetList()
{
yield return new { ContactID = 4, FullName = "Jack Smith" };
yield return new { ContactID = 5, FullName = "John Doe" };
}
public static T Cast<T>(object obj, T type)
{
return (T)obj;
}

list back
public static void Main()
{
foreach (object item in GetList())
{
var x = Cast(item, new { ContactID = 0, FullName = "" });
Console.WriteLine(x.ContactID + " " + x.FullName);
}
}
public static IEnumerable<object> GetList()
{
yield return new { ContactID = 4, FullName = "Jack Smith" };
yield return new { ContactID = 5, FullName = "John Doe" };
}
public static T Cast<T>(object obj, T type)
{
return (T)obj;
}

i would use
allContacts
.Select(c => new { c.ContactID, c.FullName })
.ToList()
.ForEach(c => {
...do stuff;
});
then you dont need to declare at all.
i believe that less declaration, less semi-colon leads to less bug

Related

Add text to all properties in all items of a list without manual multiple loops

I have a List of MyClass
public class MyClass
{
public string Title { get; set; }
public string Name { get; set; }
}
var records = new List<MyClass>
{
new MyClass { Title = "Mr", Name = "Bob" },
new MyClass { Title = "Dr", Name = "Jon" },
};
I need to add "" around each value in each property of the class, and each item in the list. So the actual content of each property contains a " at the start and end.
Is there a way I can add this without having to loop through each property & item and do it all manually. A way using Linq perhaps?
I can't find anything on Google, I'm not even really sure what to search for.
Thanks
Yes, simply map the transformation:
var transformedRecords =
records.Select(c =>
new MyClass
{
Title = $"\"{c.Title}\"",
Name = $"\"{c.Name}\""
});
Now, if what you want is a way to edit all string properties without having to manually change them one by one, then the only way is with reflection:
static void Transform<T>(T t)
where T: class
{
if (ReferenceEquals(t, null))
throw new ArgumentNullException(nameof(t));
var propertiesToEdit =
typeof(T).GetProperties(BindingFlags.Public |
BindingFlags.Instance)
.Where(p => p.PropertyType == typeof(string)
p.CanWrite &&
p.CanRead);
foreach (var p in propertiesToEdit)
{
p.SetValue(t, $"\"{p.GetValue(t)}\"");
}
}
But now you've got a method that mutates the object that is passed into it. You should never use mutating methods with LINQ, unexpected behaviors are to be expected.
So you are better of just simply iterating manually:
foreach (var r in records)
Transform(r);
And now your records list will contain the mutated items.
Of course, you don't need to stop at string, you can make this quite a bit more general with very little additional cost:
static void Transform<T, Q>(T t, Func<Q, Q> transform)
where T: class
{
if (ReferenceEquals(t, null))
throw new ArgumentNullException(nameof(t));
var propertiesToEdit =
typeof(T).GetProperties(BindingFlags.Public |
BindingFlags.Instance)
.Where(p => p.PropertyType == typeof(Q)
p.CanWrite &&
p.CanRead);
foreach (var p in propertiesToEdit)
{
p.SetValue(t, transform((Q)p.GetValue(t)));
}
}
And now you'd use it like this:
foreach (var r in records)
Transform(r, (string s) => $"\"{s}\"");
The class constraint is important here because this will fail with value types; c# defaults to pass by value semantics so the method will mutate copies, not the original instances in the list.
Without using a loop I believe this is what you seek:
records.ForEach(e =>
{
e.Name = $"\"{e.Name}\"";
e.Title = $"\"{e.Title}\"";
});

Convert LINQ return type to C# class

I have a LINQ query against my DBModel classes which is returning an anonymous type. I have to convert it to a known C# class type.
I can directly use the known type in DBModel class but it's not allowed to use any known types in my project architecture.
Example:
static dynamic getEmployees()
{
SampleDB db = new SampleDB();
var result = (from x in db.Employes
select new
{
name = x.FirstName + " " + x.LastName,
department = x.DepartmentId
});
return result;
}
My known type:
public class Emp
{
public string name { set; get; }
public int department { set; get; }
}
Program:
dynamic d = getEmployees();
List<Emp> result = d.cast<Emp>();
//Other code....
How can I cast the dynamic type to List? In getEmployees I can't use like
static List<Emp> getEmployees()
{
SampleDB db = new SampleDB();
var result = (from x in db.Employes
select new Emp
{
name = x.FirstName + " " + x.LastName,
department = x.DepartmentId
}).ToList();
return result;
}
Can anybody tell me how can I cast the LINQ return type to a known type?
Cast<> is an extension method, and those are not directly supported on dynamic objects.
You can get around that, by calling the extension method like this: Enumerable.Cast<Emp>(d), but this still would not work, there is no known cast from an anonymous type to Emp.
You could try something similar with .Select(), that should work. However the easiest way is a simple for loop
dynamic d = getEmployees();
var emps = new List<Emp>();
foreach (var emp in d)
{
emps.Add(new Emp(){name = emp.name, department = emp.department};
}
if you want to consume the collection on-demand as an IEnumerable, instead of putting it in a List, you could wrap this in a helper method:
IEnumerable<Emp> getEmps(dynamic d)
{
foreach (var emp in d)
{
yield return new Emp(){name = emp.name, department = emp.department};
}
}
There's no cast method on the dynamic type. What you should do is explicitly cast your dynamic to the required type and because in the dynamic method you have an anonimous object you'll have to do an intermediate step.
Something like:
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var json = serializer.Serialize(d);
List<Emp> result = serializer.Deserialize<List<Emp>>(json);

how to yield an anonymous class in IEnumerable.GroupBy<T> "on the fly" (without enumerating result) in C# LINQ?

I do like this now (thanks to StackOverflow):
IEnumerable<object> Get()
{
var groups = _myDatas.GroupBy(
data => new { Type = data.GetType(), Id = data.ClassId, Value = data.Value },
(key, rows) => new
{
ClassId = key.Id,
TypeOfObject = key.Type,
Value = key.Value,
Count = rows.Count()
}));
foreach (var item in groups)
{
yield return item;
}
}
IEnumerable<MyData> _myDatas;
But is possible to make faster or more "elegant" by not having last foreach loop, but yielding it when the group/anonymous class instance is created?
I would guess fastest way would be to write it open and:
sort the _myDatas
enumerate it and when group changes yield the last group
But I'm trying to learn some LINQ (and C# features in general) so I don't want to do that.
The rest of example is here:
public abstract class MyData
{
public int ClassId;
public string Value;
//...
}
public class MyAction : MyData
{
//...
}
public class MyObservation : MyData
{
//...
}
You should be able to return groups directly, though you might need to change your return type from IEnumerable<Object> to just IEnumerable.
So:
IEnumerable Get()
{
var groups = _myDatas.GroupBy(
// Key selector
data => new {
Type = data.GetType(),
Id = data.ClassId,
Value = data.Value
},
// Element projector
(key, rows) => new
{
ClassId = key.Id,
TypeOfObject = key.Type,
Value = key.Value,
Count = rows.Count()
}
);
return groups;
}
groups has the type IEnumerable< IGrouping< TKey = Anonymous1, TElement = Anonymous2 > >, so you can return it directly.

Getting the exact diff from the Ienumerable.except

I am using LINQ ENumerable.except to get the diff out of two lists of MyType. When I find a diff, I need to retrieve what was different in both base and compare list for the corresponding diff item. LIke,
I have two lists to compare
Base:
Name="1",Type="a",Switch="384347324372432"
Name="1",Type="b",Switch="43432432423"
Name="2",Type="q",Switch="4324324234"
Compare List:
Name="1",Type="a",Switch="aAAAA384347324372432"
Name="1",Type="c",Switch="23432432"
Name="2",Type="q",Switch="3423432423432"
Name="2",Type="q",Switch="4324324234"
Ouuput would be
Found diff.
Base:
Name="1",Type="a",Switch="384347324372432"
Corresponding compare value:
Name="1",Type="a",Switch="aAAAA384347324372432"
etc...
I have written my own class object, say MyType for storing these as items properties
Defined a custom comparer like
class mycomparer: System.Collections.Generic.IEqualityComparer<MyType>
{
public mycomparer() {}
public bool Equals(MyType type1, MyType type2)
{
return ( (type1.Name.ToLower() == type2.Name.ToLower()) && (type1.Type.ToLower() == type2.Type.ToLower()) (type1.Switch.ToLower() == type2.Switch.ToLower())
}
public int GetHashCode(MyType type)
{
return string.concat(type.Name, type.Type, type.Switch).ToLower().GetHashCode();
}
}
In my code, I use
MyComparer mine = new MyComparer();
IEnumerable<MyType> diff = baseList.Except(compareList,mine);
I get the diff correctly. But for the values that are different in baselist, I want to know what the corresponding value in comparelist was.
I do
foreach(Mytype type in diff)
{
Console.writeline(type.Name+type.Type+type.Switch);
}
How to I get the corresponding values for compare list.
I tried something like,
IEnumerable<MyType> compareValue = Comparelist.Where(tempFile => tempFile.Name.ToLower() == type.Name.ToLower() && tempFile.Type.ToLower() == process.Type.ToLower()
(Basically, switch is what could be different here mostly)
But the problem is, in some cases, there may be duplicate Name="" Type="", so the above where retrieves more than one item, so the corresponding comparelist value would be different.
I tried writing the diff values from Equal methods, but didnt work for me.
UPdate:
In the case when duplicate name and type are found and switch has a mismatch, I think diff is calculated correctly, but when the output is written to console, incorrect diff value is written, here is the sample.
Base:
Name="2",Type="q",Switch="4324324234"
Name="2",Type="q",Switch="3423432423432"
Compare List:
Name="2",Type="q",Switch="4324324234"
Name="2",Type="q",Switch="3423432423432dwqdwqdwqdqwdwdq"
base.except(compare) (as used in my sample code or Moho's solution) gets the diff correctly,
but with
diffSwitches.ToList().ForEach
I will get something like
base: Name="2",Type="q",Switch="3423432423432"
Compare: Name="2",Type="q",Switch="4324324234"
You see that is not the corresponding mismatch. Infact Switch="4324324234" is correctly matched. This is the problem I see.
Thanks.
Let both list be named list and list2. This is a solution:
var common = list1.Intersect(list2, new mycomparer());
var result = list1.Concat(list2)
.Except(common, new mycomparer())
.GroupBy (x => new { x.Name, x.Type } );
So both lists are concatenated, then the elements common in both lists are removed, and finally the remaining items are grouped by Name and Type.
Maybe useful to add that if MyType is a struct, you don't need the comparer, because structs are equal when their values are equal.
Try this
baseList.Except( compareList, mine ).Union( compareList.Except( baseList.Except, mine ) )
Edit after new requirements:
var baseList = new List<MyType>()
{
new MyType() { Name="1",Type="a",Switch="384347324372432" },
new MyType() { Name="1",Type="b",Switch="43432432423" },
new MyType() { Name="2",Type="q",Switch="4324324234" }
};
var compareList = new List<MyType>()
{
new MyType() { Name="1",Type="a",Switch="aAAAA384347324372432" },
new MyType() { Name="1",Type="c",Switch="23432432" },
new MyType() { Name="2",Type="q",Switch="3423432423432" },
new MyType() { Name="2",Type="q",Switch="4324324234" }
};
// matched Name/Type w/ different Switch
var diffSwitches = baseList.Join( compareList,
bl => new { bl.Name, bl.Type },
cl => new { cl.Name, cl.Type },
( bl, cl ) => new {
baseItem = bl,
compareItem = cl } )
.Where( o => o.baseItem.Switch != o.compareItem.Switch );
diffSwitches.ToList().ForEach(i => Console.WriteLine("{0}-{1}: {2}; {3}", i.baseItem.Name, i.baseItem.Type, i.baseItem.Switch, i.compareItem.Switch));
I think you can get the results you want with a slight change to your comparer:
class mycomparer : System.Collections.Generic.IEqualityComparer<Item>
{
bool customcomparer = false;
public mycomparer(bool custom = false)
{
customcomparer = custom;
}
public bool Equals(Item type1, Item type2)
{
return GetHashCode(type1) == GetHashCode(type2);
}
public int GetHashCode(Item type)
{
if (customcomparer)
return string.Concat(type.Name, type.Type).ToLower().GetHashCode();
return string.Concat(type.Name, type.Type, type.Switch).ToLower().GetHashCode();
}
}
And your class set up like this:
public class MyType
{
public String Name, Type, Switch;
public MyType()
{
}
public MyType(string _name, string _type, string _switch)
{
Name = _name;
Type = _type;
Switch = _switch;
}
public override string ToString()
{
return "Name = " + this.Name + ",Type = " + this.Type + ",Switch = " + this.Switch;
}
}
And a second IEnumerable like this:
private void button3_Click(object sender, EventArgs e)
{
mycomparer mine = new mycomparer();
mycomparer mine2 = new mycomparer(true);
IEnumerable<MyType> diff = baseList.Except(compareList, mine);
IEnumerable<MyType> diff2 = compareList.Intersect(diff, mine2);
string message = "Base:\n";
foreach (MyType item in diff)
{
message += item.ToString() + "\n";
}
message += "Corresponding compare value:\n";
foreach (MyType item in diff2)
{
message += item.ToString() + "\n";
}
MessageBox.Show(message);
}
I noticed diff returns 2 items Name 1 Type a and Name 1 Type b. This is from your original code so I left it like that.

convert a list of objects from one type to another using lambda expression

I have a foreach loop reading a list of objects of one type and producing a list of objects of a different type. I was told that a lambda expression can achieve the same result.
var origList = List<OrigType>(); // assume populated
var targetList = List<TargetType>();
foreach(OrigType a in origList) {
targetList.Add(new TargetType() {SomeValue = a.SomeValue});
}
Try the following
var targetList = origList
.Select(x => new TargetType() { SomeValue = x.SomeValue })
.ToList();
This is using a combination of Lambdas and LINQ to achieve the solution. The Select function is a projection style method which will apply the passed in delegate (or lambda in this case) to every value in the original collection. The result will be returned in a new IEnumerable<TargetType>. The .ToList call is an extension method which will convert this IEnumerable<TargetType> into a List<TargetType>.
If you know you want to convert from List<T1> to List<T2> then List<T>.ConvertAll will be slightly more efficient than Select/ToList because it knows the exact size to start with:
target = orig.ConvertAll(x => new TargetType { SomeValue = x.SomeValue });
In the more general case when you only know about the source as an IEnumerable<T>, using Select/ToList is the way to go. You could also argue that in a world with LINQ, it's more idiomatic to start with... but it's worth at least being aware of the ConvertAll option.
var target = origList.ConvertAll(x => (TargetType)x);
List<target> targetList = new List<target>(originalList.Cast<target>());
I believe something like this should work:
origList.Select(a => new TargetType() { SomeValue = a.SomeValue});
Here's a simple example..
List<char> c = new List<char>() { 'A', 'B', 'C' };
List<string> s = c.Select(x => x.ToString()).ToList();
var list1 = new List<Type1>();
var list2 = new List<Type2>();
list1.ForEach(item => list2.Add(new Type2() { Prop1 = value1 }));
Assume that you have multiple properties you want to convert.
public class OrigType{
public string Prop1A {get;set;}
public string Prop1B {get;set;}
}
public class TargetType{
public string Prop2A {get;set;}
public string Prop2B {get;set;}
}
var list1 = new List<OrigType>();
var list2 = new List<TargetType>();
list1.ConvertAll(x => new OrigType { Prop2A = x.Prop1A, Prop2B = x.Prop1B })
Or with a constructor & linq with Select:
public class TargetType {
public string Prop1 {get;set;}
public string Prop1 {get;set;}
// Constructor
public TargetType(OrigType origType) {
Prop1 = origType.Prop1;
Prop2 = origType.Prop2;
}
}
var origList = new List<OrigType>();
var targetList = origList.Select(s=> new TargetType(s)).ToList();
The Linq line is more soft! ;-)
If you need to use a function to cast:
var list1 = new List<Type1>();
var list2 = new List<Type2>();
list2 = list1.ConvertAll(x => myConvertFuntion(x));
Where my custom function is:
private Type2 myConvertFunction(Type1 obj){
//do something to cast Type1 into Type2
return new Type2();
}
for similar type class.
List<targetlist> targetlst= JsonConvert.DeserializeObject<List<targetlist>>(JsonConvert.SerializeObject(<List<baselist>));
If the types can be directly cast this is the cleanest way to do it:
var target = yourList.ConvertAll(x => (TargetType)x);
If the types can't be directly cast then you can map the properties from the orginal type to the target type.
var target = yourList.ConvertAll(x => new TargetType { SomeValue = x.SomeValue });
If casting when mapping from one list to another is required, from convertall, you can call a function to test the casting.
public int StringToInt(String value)
{
try
{
return Int32.Parse(value);
}
catch (Exception ex)
{
return -1;
}
}
[Fact]
public async Task TestConvertAll()
{
List<String> lstString = new List<String>{"1","2","3","4","5","6","7","8","9","10" };
List<int> lstInt = lstString.ConvertAll(new Converter<String, int>(StringToInt));
foreach (var item in lstInt)
{
output.WriteLine("{0}", item);
}
if (lstInt.Count()>0) {
Assert.True(true);
}
}
We will consider first List type is String and want to convert it to Integer type of List.
List<String> origList = new ArrayList<>(); // assume populated
Add values in the original List.
origList.add("1");
origList.add("2");
origList.add("3");
origList.add("4");
origList.add("8");
Create target List of Integer Type
List<Integer> targetLambdaList = new ArrayList<Integer>();
targetLambdaList=origList.stream().map(Integer::valueOf).collect(Collectors.toList());
Print List values using forEach:
targetLambdaList.forEach(System.out::println);

Categories

Resources