Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
An intro to C# for a Python developer. Made for one of my coworkers.

C# For Python Programmers

Syntax and core concepts

Basic Syntax

  • Single-line comments are started with //. Multi-line comments are started with /* and ended with */.

  • C# uses braces ({ and }) instead of indentation to organize code into blocks. If a block is a single line, the braces can be omitted. For example,

      if (foo) {
          bar();
      }
    

    can be shortened to

      if (foo)
          bar();
    

    However, avoid

      if (foo) {
          bar();
          baz();
      }
      else // matching if uses braces, but this does not
          somethingCompletelyDifferent();
    

    preferring

      if (foo) {
          bar();
          baz();
      }
      else { // matching if uses braces, so we do here even though it's one line
          somethingCompletelyDifferent();
      }
    
  • Brace style is contested. The default C# style is to have braces on their own line for everything:

      class Thing
      {
          void foo()
          {
              if (a)
              {
                  bar();
                  baz();
              }
              else
              {
                  otherThing();
              }
          }
      }
    

    The author is of the opinion that this wastes vertical screen space and that it is easier to code when you can see more on your screen, and prefers Stroustrup Style:

      class Thing {
          void foo()
          {
              if (a) {
                  bar();
                  baz();
              }
              else {
                  otherThing();
              }
          }
      }
    

    or even Java style:

      class Thing {
          void foo() {
              if (a) {
                  bar();
                  baz();
              } else {
                  otherThing();
              }
          }
      }
    

    All of these styles can be set in Visual Studio in Tools -> Options -> Text Editor -> C# -> Formatting -> New Lines

  • Statements are ended with semicolons. A statement can therefore span multiple lines without any problem. This can be useful in some cases:

      someVariable += SomeReallyLongFunctionName(longParameterOne,
                                                 longParameterTwo);
    
  • C# is a strongly-typed language. Unlike Python, variables must be explicitly declared before they are used, and you must specify their type when you declare them. Declarations take the form

      <type> <variable name>;
    

    or, to declare and initialize them in one statement,

      <type> <variable name> = <value>;
    

    This type cannot be changed. For example, if you declare an integer with

      int i = 42;
    

    you cannot later assign a string value, such as

      i = "I'm a string now!";
    

    Thankfully, when you declare and initialize a variable in the same statement, the compiler can determine the type from the right hand side of the assignment if you use the keyword var. For example,

      int port = 42;
      TcpListener listener = new TcpListener(port);
    

    can be shortened to

      var port = 42;
      var listener = new TcpListener(port);
    

    This may seem more natural to someone with experience in "weak-typed" languages like Python.

  • Because of this strong typing, data structures (such as lists, queues, trees, etc.) must be told what type they will be containing using the following syntax:

      var intList = new List<int>(); // Declares a list of ints
      var dict = new Dictionary<int, string>(); // Declares a dictionary that maps ints to strings
      // and so on...
    
  • For similar reasons, data structures cannot contain a mix of unrelated types. You cannot have a List that contians some mix of strings and integers for example. You can, of course, make a list of some base class and add instances of derived classes. Assuming Cat and Dog are derived from the Animal class, the following code is valid:

      var petList = new List<Animal>();
      petList.add(new Cat());
      petList.add(new Dog());
    

    If you are looking to contain a mix of types for a specific purpose, see the section below on user-defined types.

  • Arrays are fixed-size (you cannot append to them, use List for such cases) and take the following syntax:

      var firstTen = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // An array of the first ten positive integers
    
      // .Length will retrieve an array's length, similar to len() in Python
      if (firstTen.Length != 10)
          throw new Exception("Reality is not working properly."); // Throws an exception (see below)
    
      // Create an array of 20 integers, initialized to their default value, i.e., 0
      var empty = new int[20];
    

Control Flow:

  • if x = 0: becomes if (x == 0). Note that in C#, == is the comparison operator. A single equals is used for assignment, and the compiler will not allow it inside a conditional like if.

  • ++i is shorthand for i = i + 1. Placing ++ before or after the variable (e.g. i++) can have different effects in some situations.

  • for i in range(0, 10) becomes for (int i = 0; i < 10; ++i). This takes the form
    for (<declaration>; <continue looping while this is true>; <at the end of each iteration>).
    So, we're declaring a counter variable i, initializing it to 0, looping until it is equal to 10, and incrementing it by one each time.

  • for item in myArray becomes foreach (var item in myArray)

  • Exception handling:

      try:
          ...
      except SomeError as e:
          ...
    

    becomes

      try {
          ...
      }
      catch (SomeError e) {
          ...
      }
    
  • Throwing exceptions: raise Exception("It broke") becomes throw new Exception("It broke");.

Boolean expressions

  • Boolean values True and False are lowercase in C# (true and false)

  • C# uses symbols instead of keywords for logical operators.

    • and is &&
    • or is ||
    • not is !
  • The bitwise versions of these operators are &, |, and ~, respectively.

User-Defined datatypes

  • Like Python, C# allows the user to define their own classes with variables and methods.

    In Python:

      class MyClass(BaseClass): # Inherit BaseClass
    
           def __init__(self, foo):
              # Initialize the class with the help of the argument foo
    
           # Other contents
    
      # Elsewhere...
      # Instantiate an instance of MyClass
      instance = MyClass(42)
    

    In C#:

      class MyClass : BaseClass { // Inherit BaseClass
    
          public MyClass(int foo)
          {
              // Initialize the class with the help of the argument foo
          }
    
          // Other contents
      }
    
      // Elsewhere...
      // Instantiate an instance of MyClass
      var instance = new MyClass(42);
    
  • In Python, member methods and variables can be made "private" to the class using an __ prefix, but this just mangles their names. Nothing keeps the programmer from actually using them outside the class, who is trusted to not do this. C# has less faith in humanity and, as a consequence, provides the following accessibility levels:

    • public - All code can access this.
    • internal - Only other code in this assembly (i.e. program or library) can access this. This can be useful if you are making a library and want to make classes or methods inaccessible to the end-user.
    • protected - Only other code in this class and derived classes can access this.
    • protected internal - Only other code in this class and derived classes in this assembly can access this.
    • private - Only other code in this class can access this.
  • In C#, you cannot have free-standing, "global" functions and variables like you can in Python. Because of this, static members, which can be accessed without creating an instance of the class. Python has them as well, but they're not used as often since it allows global functions and variables.

  • C# has a feature called properties, which allow you to replace instances where you would use getX and setX style functions with a field that looks like a variable but calls the proper "getter" and "setter" methods when the value is accessed or modified:

      private int foo; // Backing member variable
      public int Foo // Properties are usually capitalized camel case
      {
          get // Called when Foo is accessed
          {
              // Any logic or updating of related state here
              // ...
    
              return foo;
          }
          Set // Called when Foo is changed
          {
              // Any logic or updating of related state here
              // ...
    
              foo = value;
          }
      }
    

    If your get and set methods do nothing but use the backing variable, C# can auto-implement the property and backing variable:

      public int Foo { get; set; }
    

    This is preferred over public member variables, as you can later modify the property if you need it to do more without changing any code that uses the property. The getter and setter can also be given different access levels:

      // A property that can only be modified inside the class that contains it:
      public int Foo { get; private set; }
    
  • While Python variables use reference-like bahavior, C# has value types as well as reference types. Value types act as individual copies of whatever data they contain, whereas reference types point to instances of the data. Classes are reference types. The programmer may also create their own value types using the struct keyword. A trivial example of all of this is below:

      // This code is not meant to be useful,
      // but just to explain the difference between value and reference types.
    
      class RefType {
          public int contents;
    
          // Trivial constructor to allow us to initialize contents
          public RefType(int c) { contents = c; }
      }
    
      struct ValType {
          public int contents;
    
          // Trivial constructor to allow us to initialize contents
          public ValType(int c) { contents = c; }
      }
    
      // Elsewhere...
      ValType val1 = new ValType(42);
      ValType val2 = val1;
      val2.contents = 20;
      // val1.contents is 42 and val2.contents is 20
      // since value types act as individual copies of whatever data they contain.
    
      RefType ref1 = new RefType(30);
      RefType ref2 = ref1;
      ref2.contnets = 1;
      // ref1.contents is 1 and ref2.contents is 1 because both references point at the same object.
    
      ref2 = null; // References can refer to nothing. null is the C# equivalent of "None" in Python.
    

    If this doesn't help, there are many online articles that explain the difference.

Resource handling

Since C# is a garbage collected language, memory will be automatically managed by the .NET runtime. Other resources, however, such as file handles, network sockets, etc. must be closed manually by the programmer. This is handled by the [IDisposable interface](http://msdn.microsoft.com/en-us/library/system.idisposable(v=vs.110\).aspx). Classes that implement this interface have a Dispose method, which can be called to close resources. C# also provide the using statement, which works similarly to Python's with statement. The following two blocks of are equivalent:

using (Font font1 = new Font("Arial", 10.0f))
{
    byte charset = font1.GdiCharSet;
}

is equivalent to

{
    Font font1 = new Font("Arial", 10.0f);
    try
    {
        byte charset = font1.GdiCharSet;
    }
    finally
    {
        if (font1 != null)
          ((IDisposable)font1).Dispose();
    }
}

Synchronization

  • Unlike most Python implementations, C# does not have a Global Interpreter Lock. This allows it to run several threads in parallel, on different CPU cores.

  • C# has locks (Python's equivalent here) built in on the language level. Any reference type (i.e. class) can be used as a re-entrant lock using the lock keyword:

      class Account {
          decimal balance;
          private Object thisLock = new Object();
    
          public void Withdraw(decimal amount)
          {
              // Everything in this block is a critical section protected by thisLock
              lock (thisLock) {
                  if (amount > balance) {
                      throw new Exception("Insufficient funds");
                  }
                      balance -= amount;
              }
          }
      }
    

    See the MSDN page for recommended guidelines.

  • C# also comes with your usual bag of tools for synchronization, such as monitors, semaphores, etc. See this.

  • Reads and writes to bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types are guaranteed to be atomic by the C# language spec. This means that you can, for example, set a bool in one thread to indicate to another thread that it should exit a loop without the use of a lock. This does not, however, mean that read-modify-write operations (such as incrementing a variable or checking it, then setting it) are atomic. Also, to be used across multiple threads in the manner described above, these variables must be declared with the volatile keyword, which forbids the compiler from caching a copy of the variable in a CPU core's registers. The link on volatile above also includes an example of the "boolean as an exit flag" approach mentioned above.

@donovankeith

This comment has been minimized.

Copy link

commented Jan 25, 2017

Thanks for writing this! I found it extremely helpful. Any chance you could use c# syntax highlighting for future revisions? It might make it a bit easier to see what's going one. Just add the keyword csharp after the start of your code block.

For example:

      public void Withdraw(decimal amount)
      {
          // Everything in this block is a critical section protected by thisLock
          lock (thisLock) {
              if (amount > balance) {
                  throw new Exception("Insufficient funds");
              }
                  balance -= amount;
          }
      }

Would become:

      public void Withdraw(decimal amount)
      {
          // Everything in this block is a critical section protected by thisLock
          lock (thisLock) {
              if (amount > balance) {
                  throw new Exception("Insufficient funds");
              }
                  balance -= amount;
          }
      }
@andybak

This comment has been minimized.

Copy link

commented May 9, 2017

This may seem more natural to someone with experience in "weak-typed" languages like Python.

Python is strongly typed by the most common definition. You're mixing up strong/weak vs static/dynamic:

https://pythonconquerstheuniverse.wordpress.com/2009/10/03/static-vs-dynamic-typing-of-programming-languages/

@andybak

This comment has been minimized.

Copy link

commented May 9, 2017

if x = 0: becomes if (x == 0)

What language treats '=' as a comparison? I can't think of anything since 8-bit BASIC interpreters.

@andybak

This comment has been minimized.

Copy link

commented May 9, 2017

In C#, you cannot have free-standing, "global" functions and variables

This is confusing. Being "global" has nothing to do with allowing functions outside of classes. One is about scope and the other is about semantics.

@jlplazar

This comment has been minimized.

Copy link

commented Aug 1, 2017

This is a good introduction, but I have one comment: the equality comparison operator in Python is not =, but ==.
The following code would produce a SyntaxError in Python.

if x = 0:

@aclinch

This comment has been minimized.

Copy link

commented Jan 18, 2018

It may interest your readers that python programmers can also have properties; see https://docs.python.org/2/howto/descriptor.html#properties .

@jabbalaci

This comment has been minimized.

Copy link

commented Apr 3, 2018

Thanks! One minor note: if you want to make something "private", we use a single underscore: _spam.

@ikem-krueger

This comment has been minimized.

Copy link

commented May 21, 2018

I fixed some typos and added syntax highlighting for code blocks: https://gist.github.com/ikem-krueger/4bb19c6aef0f80e3aae68c6b0fa1d706

@Ralithune

This comment has been minimized.

Copy link

commented Jun 13, 2018

I don't understand the following sentences, 3rd bullet under User-Defined datatypes:

In C#, you cannot have free-standing, "global" functions and variables like you can in Python. Because of this, static members, which can be accessed without creating an instance of the class.

What does that second sentence say? How do I set a global variable in C#?

@praveenkumarpgiindia

This comment has been minimized.

Copy link

commented Aug 17, 2018

Thank you so much for creating such a brilliant comparison... Can you provide more information like this?? I am a python programmer who want to learn C sharp comparing python. Do you recommend any material which makes similar comparison as yours???

@evgenybf

This comment has been minimized.

Copy link

commented Oct 23, 2018

Thanks! One minor note: if you want to make something "private", we use a single underscore: _spam.

You might have wanted to say 'double underscore', as a single underscore is for protected members in Python.

@Diapolo10

This comment has been minimized.

Copy link

commented Jan 5, 2019

I appreciate this post, but would like to point out that there's a difference between strong/weak typing and static/dynamic typing.

Python is actually strongly and dynamically typed, not weakly typed. Weak typing refers to the language automatically coercing two different types to something comparable in comparisons, such as comparing a string to an int. JavaScript is an example that does this by default without using the === operator (or equivalent for lt/gt/not). Python, on the other hand, requires the types to match unless explicitly stated otherwise.

I rest my case. :p

@i5ar

This comment has been minimized.

Copy link

commented Jan 27, 2019

@andybak

What language treats '=' as a comparison? I can't think of anything since 8-bit BASIC interpreters.

SQL, which is quite popular too (TIOBE Index).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.