Reputation: 18684
My GUI is calling a service project that does some linq work, and returns data to my GUI. However, I am battling with the return type of the method. After some reading, I have this as my method:
public static IEnumerable GetDetailedAccounts()
{
IEnumerable accounts =(from a in Db.accounts
join i in Db.financial_institution on
a.financial_institution.financial_institution_id
equals i.financial_institution_id
join acct in Db.z_account_type on a.z_account_type.account_type_id
equals acct.account_type_id
orderby i.name
select new
{
account_id = a.account_id,
name = i.name,
description = acct.description
});
return accounts;
}
However, my caller is battling a bit. I think I am screwing up the return type, or not handling the caller well, but it's not working as I'd hoped.
This is how I am attempting to call the method from my GUI.
IEnumerable accounts = Data.AccountService.GetDetailedAccounts();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Accounts:");
Console.ForegroundColor = ConsoleColor.White;
foreach (var acc in accounts)
{
Console.WriteLine(string.Format("{0:00} {1}", acc.account_id, acc.name + " " + acc.description));
}
int accountid = WaitForKey();
However, my foreach, and the acc - isn't working. acc doesn't know about the name, description and id that I setup in the method. Am I at least close to being right?
Upvotes: 4
Views: 142
Reputation: 7140
Davy8 is correct, and also creating a custom BusinessObject (AccountDetail) would be a better solution for long term external library life cycle (if you are using this AccountDetail alot in your logic/Code), since you can customize it as you want
having a transfer class (AccountDetail) easily allows you to bind back to some UI in design time and make the concept of your project a more bit clear, you can also re-use it more often
public class AccountDetail
{
public string AccountID{get;set;}
public string AccountName {get;set;}
public string AccountDescription {get;set}
public AccountDetail(){}
}
so Query is:
public static List<AccountDetail> GetDetailedAccounts()
{
return (from a in Db.accounts
join i in Db.financial_institution on a.financial_institution.financial_institution_id
equals i.financial_institution_id
join acct in Db.z_account_type on a.z_account_type.account_type_id equals
acct.account_type_id
orderby i.name
select new AccountDetail
{ AccountID = a.account_id,
AccountName= i.name,
AccountDescription= acct.description}
}).ToList();
Upvotes: 0
Reputation: 160852
The problem is that you are using an anonymous type that the user of the method has no way of casting back to. An easy way out (besides reflection or creating a class) would be using dynamic, since you know the properties you want to access are there:
Example: (very made up I admit)
public static IEnumerable GetAccounts()
{
return Enumerable.Range(0, 10)
.Select(x => new { Id = x, Name = "herbert" });
}
//...
foreach (dynamic account in GetAccounts())
{
Console.WriteLine(string.Format("Id: {0}, Name: {1}",
account.Id,
account.Name));
}
Back to your code that would mean just changing the calling code:
foreach (dynamic acc in accounts)
{
Console.WriteLine(string.Format("{0:00} {1}", acc.account_id, acc.name + " " + acc.description));
}
Upvotes: 1
Reputation: 31586
@BrokenGlass is correct that the root of the issue is that you're using an anonymous type. That results in you using the non-generic version of IEnumerable which doesn't know what type the objects are.
Rather than using dynamic
though (which requires .NET 4.0 which may or may not be an issue for you), I would recommend creating an actual Account
class.
That way you can return an IEnumerable<Account>
instead of just IEnumerable
. Then you'll be able to use the properties since it knows that it's an Account.
Once you create the Account class your method then becomes:
public static IEnumerable<Account> GetDetailedAccounts()
{
IEnumerable<Account> accounts = (from a in Db.accounts
join i in Db.financial_institution on a.financial_institution.financial_institution_id
equals i.financial_institution_id
join acct in Db.z_account_type on a.z_account_type.account_type_id equals
acct.account_type_id
orderby i.name
select new Account {account_id = a.account_id, name = i.name, description = acct.description});
return accounts;
}
Then the calling code can remain the same.
I thought I should point out that var
doesn't work the way you probably think it does. The type of the variable is still determined compile-time, which means (for the most part) it's just a shortcut. Your example would be identical to if you had used object
instead of var
because IEnumerable
can only contain object
.
If you're working in .NET I'd recommend follow .NET naming conventions though so AccountId
instead of account_id
but that won't affect whether it works or not.
Upvotes: 4