突破嵌套循环的问题

时间:2011-11-16 17:47:14

标签: c# .net

我有问题正确地打破这些嵌套循环。代码尝试做的是表明客户已经租借了某部电影。将电影和客户都与arraylist对象的属性进行比较,然后如果全部检出name属性,则将电影对象的ID属性作为字符串添加到另一个arraylist。只要我使用第一部电影(来自电影)和第一部客户(来自客户),所有这一切都能正常工作,但如果我尝试将其他电影与其他客户一起租借到我的arraylist,那么它将租借的电影添加到customerRentedMovies arraylist但打印出“其他消息”。我想我还需要打破foreach(blabla)循环吗?或者可以使用?评论被删除(看起来有点混乱,如果需要可以进一步解释)

public void RentMovie(string titel, int movieID, string name, int customerID) 
    {
        foreach (Customer customer in customers)  
        {
            if (name == customer.Name && customerID == customer.CustomerID)  
            {
                foreach (MovieInfo movie in movies)
                {
                    if (titel == movie.Titel && movieID == movie.MovieID)
                    {
                        movie.rented = true;
                        string rentedMovie = string.Format("{0}  ID: {1}", movie.Titel, movie.MovieID);
                        customer.customerRentedMovies.Add(rentedMovie); 

                        break; 
                    }

                    else { Console.WriteLine("No movie with that titel and ID!"); } 

                }
             break;      
            }
            else { Console.WriteLine("No customer with that ID and name"); } 
        }

    }

7 个答案:

答案 0 :(得分:4)

让我觉得实际上根本不需要嵌套循环 - 无论如何你都不会根据movies改变customer。另外,我使用LINQ。所以:

var customer = customers.FirstOrDefault(c => c.Name == customerName && 
                                             c.CustomerId == customerId);
if (customer == null)
{
    Console.WriteLine("No customer with that ID and name");
    return;
}

var movie = movies.FirstOrDefault(m => m.Name == movieName && 
                                  m.MovieId == movieId);

if (movie == null)
{
    Console.WriteLine("No movie with that ID and name");
    return;
}

movie.rented = true;
string rentedMovie = string.Format("{0}  ID: {1}", movie.Titel, movie.MovieID);
customer.customerRentedMovies.Add(rentedMovie);

(如果无法找到客户或电影,我可能实际更改返回的内容或抛出异常,但这是另一回事。)

重要的是,现在没有明确的循环 - 我们说我们试图找到声明性并采取相应的行动。同样地,没有嵌套,这将两个问题分开(找一部电影并找到一个顾客)。我们现在可以轻松地将每个部分提取到一个单独的方法中 - 特别是如果我们使用异常而不是记录和返回。那就是:

Customer customer = FindCustomer(customerId, customerName);
Movie movie = FindMovie(movieId, movieName);

movie.rented = true;
string rentedMovie = string.Format("{0}  ID: {1}", movie.Titel, movie.MovieID);
customer.customerRentedMovies.Add(rentedMovie);

更简单。

答案 1 :(得分:2)

您的方法违反了“单一责任”规则 - 每个类别或方法都应该只有一个责任和更改原因。你有一个方法负责做3件不同的事情:

  • 寻找客户
  • 寻找电影
  • 将电影租给客户。

这使它

  • 难以测试
  • 难以维护
  • 难以理解

这是Code Smell

您应该像这样重构您的方法,将寻找客户和查找电影的责任委托给他们自己的方法:

public void RentMovie( string titel , int movieID , string name , int customerID )
{
  Customer  customer = FindCustomer( customerID , name ) ;
  MovieInfo movie    = FindMovie( movieID , titel ) ;

  if ( customer == null )
  {
    Console.WriteLine("No customer with that ID and name");
  }

  if ( movie == null )
  {
    Console.WriteLine("No movie with that titel and ID!") ;
  }

  if ( customer != null && movie != null )
  {
    string rentedMovie = string.Format( "{0}  ID: {1}" , movie.Titel , movie.MovieID );
    movie.rented = true;
    customer.customerRentedMovies.Add( rentedMovie );
  }

  return ;
}

如果您不使用Linq,FindCustomer()FindMovie方法可能如下所示:

private MovieInfo FindMovie( int movieID , string titel )
{
  MovieInfo instance = null ;
  foreach( MovieInfo movie in movies )
  {
    if ( movie.MovieID == movieID && movie.Titel == titel )
    {
      instance = movie ;
      break ;
    }
  }
  return instance ;
}

private Customer FindCustomer( int customerID , string name )
{
  Customer instance = null ;
  foreach( Customer customer in customers )
  {
    if ( customer.CustomerID == customerID && customer.Name == name )
    {
      instance = customer ;
      break ;
    }
  }
  return instance ;
}

如果您使用Ling,则可能采用相同的方法:

private MovieInfo FindMovie( int movieID , string titel )
{
  return movies.Where( x => x.MovieID == movieID && x.Titel == titel ).SingleOrDefault() ;
}

private Customer FindCustomer( int customerID , string name )
{
  return customers.Where( x => x.Name == name && x.CustomerID == customerID ).SingleOrDefault() ;
}

现在代码更简单,更易于理解和自我描述。在进行更改时,更改也会更容易。

答案 2 :(得分:1)

如果您想要摆脱两个循环,只需使用return

foreach (Customer customer in customers)   
{ 
    if (name == customer.Name && customerID == customer.CustomerID)   
    { 
        foreach (MovieInfo movie in movies) 
        { 
            if (titel == movie.Titel && movieID == movie.MovieID) 
            { 
                movie.rented = true; 
                string rentedMovie = string.Format("{0}  ID: {1}", movie.Titel, movie.MovieID); 
                customer.customerRentedMovies.Add(rentedMovie);  

                return; //break out of both loops  
            } 
            else { Console.WriteLine("No movie with that titel and ID!"); }       
        }                         
    }                 
    else { Console.WriteLine("No customer with that ID and name"); }  
} 

答案 3 :(得分:1)

由于你在循环后没有做任何事情,你只需拨打return;即可获得休息时间。

答案 4 :(得分:0)

如果您能够使用LINQ,您的代码可以变得更加清晰:

var customer =
    customers.FirstOrDefault(x => x.Name == name && x.CustomerID == customerID);
if (customer == null) { // Error }

var movie = movies.FirstOrDefault(x => x.Title == title && x.MovieID == movieID);
if (movie == null) { // Error }

// Rental logic here

另外,ID不足以唯一地标识对象吗?

答案 5 :(得分:0)

如果您只想在“for”循环结束时显示错误,您需要设置某种标记,表示您找不到电影或其他内容。我已经改变了你的代码:

public void RentMovie(string titel, int movieID, string name, int customerID) 
    {
        bool hasCustomer, hasMovie;

        hasCustomer = false;
        hasMovie = false;

        foreach (Customer customer in customers)  
        {
            if (name == customer.Name && customerID == customer.CustomerID)  
            {
                hasCustomer = true;
                foreach (MovieInfo movie in movies)
                {
                    if (titel == movie.Titel && movieID == movie.MovieID)
                    {
                        hasMovie = true;
                        movie.rented = true;
                        string rentedMovie = string.Format("{0}  ID: {1}", movie.Titel, movie.MovieID);
                        customer.customerRentedMovies.Add(rentedMovie); 

                        break; 
                    }

                }
                if (hasMovie == false) {
                    Console.WriteLine("No movie with that titel and ID!");
                }
             break;      
            }
        }

        if (hasCustomer == false) {
            Console.WriteLine("No customer with that ID and name");
        }
    }

答案 6 :(得分:0)

如果您有25个客户,那么第一个foreach中的If / Else将会受到每个客户的影响,那么它会在找到合适的客户之前点击其他语句10次(假设合适的客户是第11个)为什么不使用linq来获取和设置值

    Customer customer = customers.FirstOrDefault(x => x.Name = name && x.CustomerID = customerID);

    if(customer != null) //will be null if customer isn't found
    {
        //DO the same thing here for the movies and once you find the 
        //movie set the properties and add to the collection
    }