Get back anonymous type [duplicate] - c#

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Accessing C# Anonymous Type Objects
Working with C# Anonymous Types
I'm using linq to entities to get id and full name from a table with customers.
public IQueryable RegresaClientesPorEmpresa(int id_emp)
{
var clientes = from c in context.clientes
where c.IDEmpresa == id_emp
select new
{
c.IDCliente,
NomComp = c.Nombres +" "+ c.ApellidoP +" "+ c.ApellidoM
};
return clientes;
}
The result is used as the datasource of a combobox, then when SelectionChangeCommitted is triggered in my combo, I want the selected item to be added to a listbox:
var clientes = operaciones.RegresaClientesPorEmpresa(2);
combo_cliente.DataSource = clientes;
combo_cliente.DisplayMember = "NomComp";
combo_cliente.ValueMember = "IDCliente";
listBox_grupo.DisplayMember = "NomComp";
listBox_grupo.ValueMember = "IDCliente";
private void combo_cliente_SelectionChangeCommitted(object sender, EventArgs e)
{
listBox_grupo.Items.Add(combo_cliente.SelectedItem);
}
Until here everything is fine. Finally I want to get all "IDCliente"'s values from all items added to my listbox, the problem is that I don't know how to do it because every item is an Anonymous data type. Can anyone help me?

The scope of an anonymous type is limited to the method in which it is "declared" (well it's not really declared, but you see what I mean). If you want to use the result of your query in another method, create a named type to hold the results.

You shouldn't return anonymous types from your methods if you're expecting to access their properties. It'll be easier on you if you define a class instead, because that establishes the contract of your method.

just create a class to avoid anonymous type.
class Foo
{
public string NomComp {get ; set;}
public string IDCliente {get ; set;}
}
and do
select new Foo
{
...
}
to save some hassle.
or You can define
T Cast<T>(object obj, T type)
{
return (T)obj;
}
and then use
object anonymousObject = GetSelection();
var selection = Cast(anonymousObject , new { IDCliente="", NomComp ="" });
and then you should be able to do selection.NomComp to get the property value.

Related

Cannot implicitly convert type 'System.Collections.Generic.List<<anonymous type>>' to 'System.Collections.Generic.List<string>'

my code supposed to check two conditions and return the values but when i try to return q this error shows up
Cannot implicitly convert type 'System.Collections.Generic.List<< anonymous type: string Name, string File>>' to 'System.Collections.Generic.List< string>
and i tried everything but nothing worked also don't know to set List<string> or set it as List<EF_Model.PDF> ,PDF is a DTO in my model
this is my code
internal List<string> Customers_File(int _id)
{
using (var Context = new EF_Model.CoolerEntities())
{
var q = from c in Context.Customers
where c.Id == _id &&
c.Ref_PDF != null
select new { c.PDF.Name, c.PDF.File };
return q.ToList();
}
}
You have to convert the anonymous object into a string representation.(Note I'm using C# 6.0 feature - string interpolation, you can replace it with string.Format in the previous versions.
Example:
return q.Select(x=>$"Name = {x.PDF.Name} File = {c.PDF.File}").ToList();
You have declared your return type as string but are returning an a list of anonymous objects with two properties. That won't work. If you want to return a string you need to create a single string per list item. If you want to return object change your return type
You are getting this error because you have defined Customers_File as returning a list of strings. However, the list q that you return doesn't fit that description.
In your query, when you do
select new { c.PDF.Name, c.PDF.File };
..you are making an Anonymous Type, and storing it in the collection q. This type has two fields and is clearly not a string.
Some possible solutions are:
Change your method to have return type List<object> instead of List<string> (not recommended).
Make your object into a string via some form of serialization (JSON or XML).
Create a class or struct for this data and change the return type of your method to List<dataClass>
You need to define an object with your to properties
public class PdfInfo
{
public string Name{get;set;}
public string File{get;set;}
}
Return a list of them from your method
internal List<PdfInfo> Customers_File(int _id)
And finally project to those, in place of an anonymous object:
....
select new PdfInfo() { Name=c.PDF.Name, File = c.PDF.File };

How can I get the type of the results of a LINQ query before executing it?

When EntityFramework executes a LINQ query, if query returns somethings as dynamic class, I can't get real type of result.
I have an abstract class:
abstract class Person
{
public string Name { get; set; }
//and about 1000 other properties
}
And 2 derived classes:
class RealPerson : Person
{
public void Print()
{
Console.WriteLine("Type=RealPerson, Name=" + Name);
}
}
class LegalPerson : Person
{
public void Print()
{
Console.WriteLine("Type=LegalPerson, Name=" + Name);
}
}
My LINQ TO SQL query:
var lst =
EFContext.Persons.Select(item=> new { DynamicClass_Name = item.Name }).ToList();
Now for every item in lst, I need to know type of its class to cast this item as that type, but item.GetType() returns a dynamic type.
For example assume that one of items of lst is RealPerson (called dynamicTypeItem), so if I know type of it is RealPerson I will cast this dynamicTypeItem to RealPerson using this code:
var value = dynamicTypeItem.GetType().GetProperty("DynamicClass_Name").GetValue(dynamicTypeItem);
var result = (RealPerson)Activator.CreateInstance(typeof(RealPerson));
result.GetType().GetProperty("Name").SetValue(result, value);
But I don't know type of this dynamicTypeItem (It has a dynamic type);
How to realize type of every item of lst?
It is very important that the above query selects only and only 1 property (Name property) of entities, so I can't use this code:
var lst =
EFContext.Persons.ToList().Select(item=> new { DynamicClass_Name = item.Name, Type=item.GetType() });
So I need knowing type of every item of lst before converting this item to dynamic type.
EDIT1
more explanation: result can't be Person because Person is abstract. result is RealPerson or LegalPerson, And when I select only one of properties of RealPerson or LegalPerson during convertion strongly type to anonymous type the type of original entity is missed.
You want to elicit the type from the value of one property of a database table? There is no way to select the type from that, since the type information is not fetched from database.
If you explain what it is you really need we might still be able to help you, but this constraint:
It is very important that the above query selects only and only 1 property (Name property) of entities
makes what you are trying to achieve impossible. You must select something more from the database.
How I could imaging doing it, although I would have a look at database design first if that is at all possible:
public partial class Person {
public Person() {
_dotnetType = this.GetType().Fullname;
_dotnetAssembly = this.GetType().Assembly.Fullname;
}
private string _dotnetType;
private string _dotnetAssembly;
public string DotNetType { get { return _dotnetType; } set { _dotnetType = value } }
public string DotNetAssembly { get { return _dotnetAssembl; } set { _dotnetAssembly = value } }
}
// Example usage
var peeps = from person in Entities.Persons
select new { Name = person.Name, Type = DotNetType, Assembly = DotNetAssembly };
var loadedPeople = peeps.ToList() // enumerate it
.Select( p => {
var instance = Activator.CreateInstance(p.Assembly, p.Type);
var property = p.GetType().GetProperties().First(prop => prop.Name == "Name");
property.SetValue(instance, p.Name, null);
});
I haven't tried this code, but it should work, just ensure that the parameterless constructor in Person gets called. The key point is that the database will "lose" the type information, so its better to store it as strings. Do remember that you need to add the columns to the database as well and map them!
This looks like an XY problem. Your question is, how do I instanciate objects from a table using Entity Frame (AND NOT Linq To SQL), where I have a discriminator?
The answer is simple.
YOU DON'T!
Use Single Table inheritance for your Entity Framework model and your LinqToEntities queries would be pretty simple.
Once you have that, there should be absolutely NO REASON WHAT SO EVER FOR YOUR PROJECTION.
You should be think about objects and not tables with an ORM.
So you could do the following to get all LegalPersons with name 'Alice'
var legallyAlices = EFContext.Persons.OfType<LegalPerson>()
.Where(x => x.Name == 'Alice');
OR
var legallyAlices = from legalPerson in EFContext.Persons.OfType<LegalPerson>()
where legalPerson.Name == 'Alice'
select legalPerson;

C# Anonymous Type access from other method

i've a ComboBox where is filled using a Collections of Anonymous Type:
var results = (from row in data.Tables[0].AsEnumerable()
select new {
Id = row.Field<int>("id"),
Name = row.Field<string>("Name
}).Distinct();
myComboBox.ValueMember = "Id";
myComboBox.DisplayMember = "Name";
foreach (var n in results)
{
myComboBox.Items.Add(n);
}
Then, in SelectedIndexChanged method of the comboBox, i want to retrieve the Id of the selected item, but i can't access to the "Id" property, in myComboBox.SelectedItem is the selected object.
private void myComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (myComboBox.SelectedItem != null)
{
var x = myComboBox.SelectedItem;
¿¿¿ ???
}
}
Any ideas?
Since you use Id as valuemember the Id would be stored as myComboBox.SelectedItem.Value
You can use reflection too.
private void myComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (myComboBox.SelectedItem != null)
{
var x = myComboBox.SelectedItem;
System.Type type = x.GetType();
int id = (int)type.GetProperty("Id").GetValue(obj, null);
}
}
I read an article this morning that explained exactly this:
http://blog.filipekberg.se/2011/10/06/playing-with-anonymous-types-in-c/
The idea is that you need to return a "dynamic" type.
dynamic GetAnonymousType()
{
var person = new { Name = "Filip" };
return person;
}
if you are working with C# 4.0, then use dynamic keyword, otherwise, define a class which contains id and name instead of using anonymous type, or use reflection.
Do you need the simplest solution? Create a class called SimpleEntity with three fields: Id, Description and Tag. This class should have a constructor that accept an Object and, using reflection, you get Id and Name and set the two fields. And you alse set the Tag property with the Object. In this way, you just need to populate the combo using this new class and then you get back the original object.
I hope it helps.
I think you would be better off using something like a Tuple<int, string> here, not an anonymous type, but it is possible to do what you want. Two anonymous types in the same assembly that have the same field names and field types in the same order are internally "folded" into a single type. You can use this to pass anonymous type instances around and, using generic type inference, typecast them at a later date.
Note that this relies on an internal mechanism in the C# compiler, so there's no guarantee it will continue to work; it works, however, in every current version of C# that has anonymous types.
Update: This is actually called out explicitly in the C# spec, so this should be completely safe to do:
Within the same program, two anonymous object initializers that specify a sequence of properties of the same names and types in the same order will produce instances of the same anonymous type
Note also that this only works within a single assembly (don't let the spec's reference to a "program" confuse you). To consume anonymous types from another assembly requires reflection (and, IMO, is generally a very bad idea.) However, for data binding scenarios such as yours, it works fine.
public object foo;
public void Create()
{
this.foo = new { Id = 1, Name = "Melvin" };
}
public void Consume()
{
var x = new { Id = 0, Name = String.Empty };
var y = this.Cast(this.foo, x);
}
public T Cast<T> ( object o, T template )
{
return (T)o;
}
You can use dynamic keyword instead of var.

linq casting to object

I have a linq query as follow:
public static ViewUserDisplayPreferences GetUserDisplayPreferences(int TheUserID)
{
using ( MyDataContext TheDC = new MyDataContext() )
{
var OutputUserDisplayPreferences = from user in TheDC.Users
where user.UserID == TheUserID
select new ViewUserDisplayPreferences
{
UserTimeFormat = user.UserTimeDisplay
};
return (ViewUserDisplayPreferences)(OutputUserDisplayPreferences);
}
}
For the moment, the object ViewUserDisplayPreferences is defined as follow (more variables will be added later):
public class ViewUserDisplayPreferences
{
public string UserTimeFormat { get; set; }
};
On the return statement at runtime, I get this error:
Unable to cast object of type
'System.Data.Linq.DataQuery`1[ObjectsUsers.ViewUserDisplayPreferences]'
to type
'ObjectsUsers.ViewUserDisplayPreferences'.]
What's wrong with the code? The intellisense is not showing any error on the line?
Thanks
OutputUserDisplayPreferences is an IEnumerable<T>. If you want an object, use either the First (if there can be more than one) or Single (if you know for sure only one object will be in the sequence) method on the sequence. If it is possible for the sequence to be empty, use the respective *OrDefault method.
Linq returns a collection. Try adding a .FirstOrDefault to the end.

LINQ: How to declare IEnumerable[AnonymousType]?

This is my function:
private IEnumerable<string> SeachItem(int[] ItemIds)
{
using (var reader = File.OpenText(Application.StartupPath + #"\temp\A_A.tmp"))
{
var myLine = from line in ReadLines(reader)
where line.Length > 1
let id = int.Parse(line.Split('\t')[1])
where ItemIds.Contains(id)
let m = Regex.Match(line, #"^\d+\t(\d+)\t.+?\t(item\\[^\t]+\.ddj)")
where m.Success == true
select new { Text = line, ItemId = id, Path = m.Groups[2].Value };
return myLine;
}
}
I get a compile error,because "myLine" is not a IEnumerable[string] and I don't know how to write IEnumerable[Anonymous]
"Cannot implicitly convert type 'System.Collections.Generic.IEnumerable[AnonymousType#1]' to 'System.Collections.Generic.IEnumerable[string]'"
You cannot declare IEnumerable<AnonymousType> because the type has no (known) name at build time. So if you want to use this type in a function declaration, make it a normal type. Or just modify your query to return a IENumerable<String> and stick with that type.
Or return IEnumerable<KeyValuePair<Int32, String>> using the following select statement.
select new KeyValuePair<Int32, String>(id, m.Groups[2].Value)
I am not necessarily recommending this...
It is a kind of subversion of the type system but you could do this:
1) change your method signature to return IEnumerable (the non generic one)
2) add a cast by example helper:
public static class Extensions{
public static IEnumerable<T> CastByExample<T>(
this IEnumerable sequence,
T example) where T: class
{
foreach (Object o in sequence)
yield return o as T;
}
}
3) then call the method something like this:
var example = new { Text = "", ItemId = 0, Path = "" };
foreach (var x in SeachItem(ids).CastByExample(example))
{
// now you can access the properties of x
Console.WriteLine("{0},{1},{2}", x.Text, x.ItemId, x.Path);
}
And you are done.
The key to this is the fact that if you create an anonymous type with the same order, types and property names in two places the types will be reused. Knowing this you can use generics to avoid reflection.
Hope this helps
Alex
The method signature on SearchItem indicates that the method returns an IEnumerable<string> but the anonymous type declared in your LINQ query is not of type string. If you want to keep the same method signature, you have to change your query to only select strings. e.g.
return myLine.Select(a => a.Text);
If you insist on returning the data selected by your query, you can return an IEnumerable<object> if you replace your return statement with
return myLine.Cast<object>();
Then you can consume the objects using reflection.
But really, if your going to be consuming an anonymous type outside the method that it is declared in, you should define a class an have the method return an IEnumerable of that class. Anonymous types are convenience but they are subject to abuse.
Your function is trying to return IEnumerable<string>, when the LINQ statement you are executing is actually returning an IEnumerable<T> where T is a compile-time generated type. Anonymous types are not always anonymous, as they take on a specific, concrete type after the code is compiled.
Anonymous types, however, since they are ephemeral until compiled, can only be used within the scope they are created in. To support your needs in the example you provided, I would say the simplest solution is to create a simple entity that stores the results of your query:
public class SearchItemResult
{
public string Text { get; set; }
public int ItemId { get; set; }
public string Path { get; set; }
}
public IEnumerable<SearchItemResult> SearchItem(int[] itemIds)
{
// ...
IEnumerable<SearchItemResult> results = from ... select new SearchItemResult { ... }
}
However, if your ultimate goal is not to retrieve some kind of object, and you are only interested in, say, the Path...then you can still generate an IEnumerable<string>:
IEnumerable<string> lines = from ... select m.Groups[2].Value;
I hope that helps clarify your understanding of LINQ, enumerables, and anonymous types. :)
Return a ValueTuple instead of an anonymous class. Ex (using "named tuples")-
(Text: line, ItemId: id, Path: m.Groups[2].Value)
https://learn.microsoft.com/en-us/dotnet/csharp/tuples
Instead of-
new { Text = line, ItemId = id, Path = m.Groups[2].Value }
The ValueTuple is part of C# version 7 and was originally implemented as a separate NuGet package (System.ValueTuple). Starting with .NET 4.7 it is a built-in type. For .NET Core, versions prior to 2.0 required the NuGet package but it is built-in with version 2.0.
The question was asked a long time ago, I hope it helps someone...
"You cannot declare IEnumerable", instead, must convert it to a "custom" IEnumerable:
public class MyString
{
public string String { get; set; } = string.Empty;
}
public IEnumerable<MyString> GetMyStrings(List<string> Strings)
{
var AnonString = from S in Strings group S by S into Grouped select new { String = Grouped.Key };
IEnumerable<MyString> Result = AnonString.Select(x => new MyString() { String = x.String }).ToArray();
return Result;
}
Regards.
this link could be useful for others who end up here
https://idreesdotnet.blogspot.com/2019/08/c-how-to-create-list-of-anonymous-type.html
the first solution (of 6) is delightlfully simple
1: First create the object(s) of anonymous type and then pass it to an array and call ToList() method.
var o1 = new { Id = 1, Name = "Foo" };
var o2 = new { Id = 2, Name = "Bar" };
var list = new[] { o1, o2 }.ToList();

Categories

Resources