2

I want to translate following c++ code into c#. But I do not know how to loop through "FILM" (like film [n] in c++), instead of each one calling separately.

Can someone also make the suggestion for better translation of this code?

C++ Code

// array of structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

struct movies_t {
  string title;
  int year;
} films [3];

void printmovie (movies_t movie);

int main ()
{
  string mystr;
  int n;

  for (n=0; n<3; n++)
  {
    cout << "Enter title: ";
    getline (cin,films[n].title);
    cout << "Enter year: ";
    getline (cin,mystr);
    stringstream(mystr) >> films[n].year;
  }

  cout << "\nYou have entered these movies:\n";
  for (n=0; n<3; n++)
    printmovie (films[n]);
  return 0;
}

void printmovie (movies_t movie)
{
  cout << movie.title;
  cout << " (" << movie.year << ")\n";
}

My c# attemp

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MAKEGROUP {
    class Program {
        struct movies_t {
            public string title;
            public int year;

            public  void printmovie(movies_t movie) {
                Console.Write(movie.title);
                Console.Write(" (");
                Console.Write(movie.year);
                Console.Write(")\n");
            }
        }

        static void Main(string[] args) {

            movies_t FILM = new movies_t();
            movies_t FILM1 = new movies_t();
            FILM1.title = "Hero";
            FILM1.year = 1990;

            movies_t FILM2 = new movies_t();
            FILM2.title = "Titanic";
            FILM2.year = 1997;

            movies_t FILM3 = new movies_t();
            FILM3.title = "Mission impossible";
            FILM3.year = 1996;

            // How can I use for loop 
            // for the following code

            FILM.printmovie(FILM1);
            FILM.printmovie(FILM2);
            FILM.printmovie(FILM3);

            Console.ReadKey();
        }
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
Shahgee
  • 3,303
  • 8
  • 49
  • 81
  • 5
    I wouldn't try to port the C++ directly to C#. They have different idioms. Mutable structs in C# are almost always a bad idea. An idiomatic port of the *aims* of the C++ code would look very little like this. – Jon Skeet Dec 03 '17 at 18:49

4 Answers4

4

Here is what you should do:

  • Replace struct with a class - unlike C++, C# makes a deeper distinction between structs and classes. In this case a class is more appropriate
  • Give your class a constructor - this would help you protect year and title properties from being changed after construction
  • Make an array of your classes - do this instead of creating FILM1, FILM2, and FILM3.
  • Optionally, give your class a ToString() methid - this would let you print instances of your class easier.

The class would look like this:

class Film {
    string Title {get;}
    int Year {get;}
    public Film(string title, int year) {
        Title = title;
        Year = year;
    }
}

Array initialization would look like this:

Film[] film = new Film[] {
    new Film("Hero", 1990)
,   new Film("Titanic", 1997)
,   new Film("L'Arroseur Arrosé", 1895)
};
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

Here's how you would minimally rewrite that:

var films = new List<movies_t>();

var hero = new movies_t { 
    title = "Hero",
    year = 1990
};

films.Add(hero);

//  Similar syntax for the same thing:
fiilms.Add(new movies_t { title = "Titanic", year = 1997 });

But you should be making other changes too.

Don't make movies_t a struct. Make it a class. struct means something different in those two languages. And please use C# naming conventions.

In C#, your code should look more like this:

public class Movie
{
    public Movie() 
    {
    }

    public Movie(string title, int year) 
    {
        this.Title = title;
        this.Year = year;
    }

    public string Title;
    public int Year;

    public override String ToString()
    {
        return $"{Title} ({Year})";
    }
}

//  ...snip...

var films = new List<Movie>();

var hero = new Movie("Hero", 1990);

films.Add(hero);

//  Similar syntax for the same thing:
films.Add(new Movie("Titanic", 1997));

foreach (var film in films)
{
    //  This will call Movie.ToString() to "convert" film to a string. 
    Console.WriteLine(film);
}
1

Here the working code, tested with linqpad (explanation follows):

void Main()
{
    var films = new List<Movie> {
        new Movie("Hero",1990 ),
        new Movie("Titanic",1997 ),
        new Movie("Mission impossible",1996 ),
    };

    foreach(var film in films)
    {
        Console.WriteLine(film.GetCompleteTitle());
    }
}


class Movie
{
    public String Title { get; }
    public Int32 Year { get; }

    public Movie(String title, Int32 year) => (Title, Year) = (title, year);

    public String GetCompleteTitle() => $"{Title} ({Year})";
}

Explanation:

  1. Array are not necessary if the size can change and you want to make the initialization more readable
  2. You should use a class, you don't need a value type to handle the movie concept
  3. Use the constructor to give only one way to initialize the variable
  4. Try avoid coupling your class with the console by moving the print outside the method
  5. Hide the fields and make it read only with the auto-implemented properties to hide the field implementation detail
  6. You can use string interpolation to compose the string in a readable way
  7. Expression-bodied members can be used to return methods or assign with less code
  8. Tuple deconstruction can be used to assign both the constructor parameters to the properties and keep the code more compact
Giulio Caccin
  • 2,962
  • 6
  • 36
  • 57
1
public static void Main()
{
    Movie[] movies = new Movie[]
    {
        new Movie("Hero", 1990),
        new Movie("Titanic", 1997),
        new Movie("Mission Impossible", 1996),
    };

    for (Int32 i = 0; i < movies.Length; ++i)
        Console.WriteLine(movies[i].ToString());
}

Also, use class instead of struct, since it's more appropriate (for more information read this). Here is what I suggest you (conforming to the worked example above):

public class Movie
{
    public String Title { get; private set; }
    public Int32 Year { get; private set; }

    public Movie(String title, Int32 year)
    {
        Title = title;
        Year = year;
    }

    public override String ToString()
    {
        return (title + " (" + year.ToString() + ")");
    }
}
Tommaso Belluzzo
  • 23,232
  • 8
  • 74
  • 98