2011-01-08 12 views
4

私のGUIは、いくつかのlinq作業を行い、GUIにデータを返すサービスプロジェクトを呼び出しています。しかし、私はメソッドの戻り値の型と戦っています。いくつかの読書の後、私は私の方法としてこれを持っています:Linqと戻り値の型

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; 
} 

しかし私の発信者は少し戦っています。私は、戻り値の型をうんざりしている、または呼び出し元をうまく処理していないと思うが、私が望むようにうまくいかない。

これは私の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(); 

ただし、私のforeachとacc - は機能しません。 accは、メソッドで設定した名前、説明、IDについてはわかりません。少なくとも私は正しいことに近いですか?

+0

いいえ、同じプロジェクトですが、別々のプロジェクトに分割したいと思います。だから今は別々のものだとします。 – Craig

+0

あなたのサービスはリモートにありますか?この引数型の代わりに 'var'を使うほうが良いでしょう。 –

+0

私は多分、むしろむしろ "転送オブジェクト"を持つ共有クラスのlibを構築する必要がありますかと思います。私の方法では、データを取得し、List にロードして返します。 linqを実行するプロジェクトとGUIの両方が型を知るでしょうか? – Craig

答えて

4

@BrokenGlassは、問題の根本は、あなたが匿名型を使用していることであるということが正しいです。その結果、オブジェクトの型がわからない非汎用バージョンのIEnumerableが使用されます。

dynamicを使用するのではなく(実際には.NET 4.0が必要な場合があります)、実際のAccountクラスを作成することをおすすめします。

そうすれば、IEnumerableの代わりにIEnumerable<Account>を返すことができます。それで、それがアカウントであることを知っているので、プロパティを使うことができます。あなたはAccountクラスを作成したら

あなたの方法は、次のようになります。

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; 

} 

はその後、呼び出し元のコードは同じまますることができます。

私は、varがおそらくあなたが思うように動作しないことを指摘しなければならないと思いました。変数の型はコンパイル時に決定されます。つまり、ほとんどの場合、単なるショートカットです。 IEnumerableにはobjectしか含まれていない可能性があるため、varの代わりにobjectを使用した場合と同じになります。

.NETで作業している場合は、account_idの代わりにAccountIdという名前の.NET命名規則に従うことをお勧めしますが、それは動作するかどうかには影響しません。

+0

ニース、ありがとう。だから、データ転送オブジェクトはここでは適切なソリューションでしょうか?私が必要とする(ID、名前、説明)プロパティを持つ、 'AccountDetail'と呼ばれる共有ライブラリのクラスを宣言するかもしれません。リストを返しますか? GUIプロジェクトとデータサービスプロジェクトの両方で共有ライブラリへの参照があるため、AccountDetailオブジェクトは両側で「既知」です。 – Craig

+1

@cdotlister正しい。 '動的な'解決策は機能するかもしれませんが(私はその機能に慣れていませんが、BrokenGlassが彼の話を知っていると仮定します)、実際のクラスを作成することは、プロパティの削除/ 。実際のクラスであるため、Intellisenseのサポートを受けることもできます。 – Davy8

+0

私は、クラスを具体的なクラスにリファクタリングすることができる無料のvs2010アドインがあると思いますが、私はオフィスにいないので名前を参照することはできません。あなたがこれを頻繁に行う必要がある場合、多分何かを見てください。 – asawyer

1

問題は、メソッドのユーザーがキャストバックできない匿名型を使用していることです。簡単な方法アウト(反射以外またはクラスを作成する)dynamicを使用されるだろう、あなたはあなたがアクセスするプロパティがあります知っているので:

例:(非常に私が認める最高製)

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)); 
} 
戻るだけで、呼び出し元のコードを変更することを意味しますあなたのコードに

foreach (dynamic acc in accounts) 
{ 
    Console.WriteLine(string.Format("{0:00} {1}", acc.account_id, acc.name + " " + acc.description)); 
} 
+0

「OP」は正確なコードを提供していないか、コンパイルできません。どのようにIEnumerableを反復してアカウントを取得できますか?私はこの行を意味します: 'Console.WriteLine(string.Format(" {0:00} {1} "、acc.account_id、acc.name +" "+ acc.description))'これはコンパイルできません。 –

+0

@Saeed:それは彼が解決しようとしている問題です。 – BrokenGlass

+0

それはacc.account_idを解決できないので、コンパイルしていないのです。申し訳ありませんが明確ではありません。 – Craig

0

Davy8が正解で、カスタムBusinessObject(AccountDetail)を作成すると、長期的な外部ライブラリライフサイクル(このAccountDetailをロジック/コードで使用している場合)それあなたが
が転送クラス(AccountDetail)を有するたいと簡単にあなたはそれがより頻繁に

public class AccountDetail 
{ 
public string AccountID{get;set;} 
public string AccountName {get;set;} 
public string AccountDescription {get;set} 

public AccountDetail(){} 
} 
あなたはまた、再使用することができ、設計時に戻っていくつかのUIにバインドすると、プロジェクトのコンセプトがより少し明確にすることができます

クエリは:

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();