2012-04-11 29 views
5

私は答えが見つからない質問があります。Java拡張forループ.NETループforeach

class Car { 
    /* car stuff */ 
} 

そしてJavaの

class Truck extends Car { 
    /* truck stuff */ 
} 

と、次の作品だけで罰金のC#ではC#

class Truck : Car { 
    /* truck stuff again */ 
} 

中:

我々はJavaやC#のいずれかで、次のコードを持っているとしましょう
List<Car> carList = new List<Car>(); 
//add some objects to the collection 
foreach(Truck t in carList) 
    //do stuff with only the Truck objects in the carList collection 

これは、TruckがCarのサブクラスであり、簡単に言えば、各TruckもCarであることを意味します。しかし、そのタイプのチェックが行われ、carListからTrucksのみが選択されます。

我々はJavaで同じことをしようとした場合、以下の理由強化ループ内のコードの

List<Car> carList = new ArrayList<Car>(); 
//add some objects to the collection 
for(Truck t : carList) 
    //**PROBLEM** 

を、コードでもコンパイルされません。代わりに、私たちは、同じ効果を得るために、このような何かをする必要があります:

for(Car t : carList) 
    if(t instanceof Car) 
     //cast t to Truck and do truck stuff with it 

それは、C#で問題なく動作しますが、Javaでは、あなたが余分なコードを必要とする同じ考えです。構文はほとんど同じです! Javaで動作しない理由はありますか?

+1

すべてのトラックが車ではなく、すべての車がトラックである...ではC#の変換は、実行時に試されていますが、する必要がありますので、これは、C#でもとてもきれいではありません本当にそれに慎重。 Javaはもっと慎重に思えますし、プログラマが最初にチェックすることを望んでいます(もちろん、C#のバージョンは、あなたが何をしているのか分かっていればいくつかの利点があります)。 –

+0

C#では、各オブジェクトの型がチェックされます。トラックの場合、foreachループの本体が入力されます。そうでない場合は、ループの本体が入力されます。それについて何が清潔でないのですか?私はそれをチェックするか(Java)、ランタイムはそれをチェックして(C#)、それは同じ最終結果です。 – alegen

+0

@alegen、それは真実ではありません。 –

答えて

7

事はありますが、そのタイプチェックが行われ、carListからトラックのみが選択されています。

いいえ、そうではありません。リストにTruck以外のものが含まれていると、C#で実行時例外が発生します。基本的には、C#で、

foreach(object _t in carList) { 
    Truck t = (Truck)_t;  // throws an InvalidCastException if _t is not a Truck 
    ... 
} 

などは、以下の

foreach(Truck t in carList) { 
    ... 
} 

振る舞うJavaの変異体は、他の一方で、タイプセーフです:あなたは、キャストや型チェックを自分で作る必要があります。


なぜJavaとC#の動作が異なるのですか?これは私の推測です:

C#はgenericsを持っていた前にforeachというキーワードを持っていました。したがって、List<Car>を持つ可能性はありませんでした。 C#はforeachのJavaの道を選んだいた場合は、迷惑です

foreach(object _c in myArraylistContainingOnlyCars) { 
    Car c = (Car)_c; 
    // do something with c 
} 

を書く必要があるだろう。一方、拡張されたforループとジェネリックスは、同じバージョン(Java 5)でJavaに導入されたため、自動キャストの必要はありませんでした。C#ので

+0

なので、リストにTruckオブジェクトがない場合は例外がスローされますか? – alegen

+1

いいえ、それにトラック以外のオブジェクトがある場合、例外がスローされます –

+0

それは試してみて、あなたは正しいです...あなたの答えをありがとう、私のC#でブラッシュアップする必要があります! – alegen

4

、あなたが

foreach(Truck t in carList) 

を書くとき何をコンパイラが理解することは(おおよそ)です:

var enumerator = carList.GetEnumerator(); 

while (enumerator.MoveNext()) 
{ 
    Truck t = (Truck)enumerator.Current; 
    // do stuff 
} 

carListが非トラックの車が含まれている場合、割り当てが実行時に失敗します。

あなたは説明するために、次のコンソールアプリケーションを試すことがあります。

namespace ConsoleApplication1 
{ 
    class Car 
    { 
    } 

    class Truck: Car 
    { 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Car[] cars = new[] { new Car(), new Truck() }; 

      foreach (Truck t in cars) 
      { 
       Console.WriteLine("1 truck"); 
      } 

      Console.Read(); 
     } 
    } 
} 

言語を設計する際にさまざまな選択が行われているので、C#とJavaのコンパイラは異なり、ここで動作します。奇妙なことに、「可能な限りコンパイル時にできるだけ早く失敗する」というのは、C#仕様の一般的なガイドラインです。ここでは、それが適用されない場合と、C#言語が好きなだけ、私はJavaの動作を好むところです。列挙がフィルタリングされ、唯一のトラックがループにそれを行います

foreach (Truck t in carList.OfType<Truck>()) 
{ 
    //do stuff 
} 

その方法:

しかし、C#で、LINQは、あなたがそれを持っていたと思っfunctionnalityを達成するための簡単な方法を提供します。

2
List<Car> carList = new ArrayList<Car>(); 
//add some objects to the collection 
for(Truck t : carList) 
    //**PROBLEM** 

Java 5で導入されたJava Genericsは、.NETジェネリックとは少し異なります。

短いストーリー - このようなコードを書くことはできません。これはコンパイル時エラーです。 あなたは車のリストを持っていて、トラックのリストを取得しよう - それも正しいアプローチは、そのCarインタフェースを介してTruckクラスを使用することです

/

間違って聞こえます。 (メソッドやメソッドの意味が違うだけでは)十分でない場合は、リストをフィルタリングするか(反復する前に)フィルタをかけるか、クラスを再設計してください。

1

Carの代わりにTruckクラスを使用しているのでプログラムはコンパイルされません。

あなたはこのように行うことができます。この1

for(Car t : carList) { 
    if(t instanceof Car) 
     // Do stuff here 
} 

の必要はありません:

List<Truck> truckList = new ArrayList<Truck>(); 

for(Car car : truckList) { 
    // Do stuff here 
} 

またはこの:

あなたはこのように行う場合

for(Car t : carList) { 
    // Do stuff here 
} 

それはします作品は、

List<Car> carList = new ArrayList<Car>(); 

for (Iterator<Car> it = carList.iterator(); it.hasNext();) { 
    Truck car = (Truck) it.next(); 
    // Do stuff here 
} 

の代わりにこの:

List<Car> carList = new ArrayList<Car>(); 

for(Truck truck : carList) { 
    // Do stuff here 
}