C#

Table of Contents

C#, .Net and Mono

Reference

Accessibility Levels

Array

int[] array = new int[] {10, 20, 30, 40};
for (int i = 0; i < array.Length; i++)
{
    MessageBox.Show (array[i]);
}

Array.Resize(ref array, 3);

foreach (int element in array)
{
    Console.WriteLine(element);
}
int[,] array = new int[4, 2];
int[, ,] array1 = new int[4, 2, 3];

int[, ,] array3D = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } },
                                 { { 7, 8, 9 }, { 10, 11, 12 } } };
// The same array with dimensions specified.
int[, ,] array3Da = new int[2, 2, 3] { { { 1, 2, 3 }, { 4, 5, 6 } },
                                       { { 7, 8, 9 }, { 10, 11, 12 } } };

// Access like this:
System.Console.WriteLine(array3D[1, 1, 2]);
System.Console.WriteLine(array3Da[1, 0, 1]);
int[,,] a = new int[10,11,12];
Console.WriteLine(a.Length);           // 1320
Console.WriteLine(a.GetLength(0));     // 10
Console.WriteLine(a.GetLength(1));     // 11
Console.WriteLine(a.GetLength(2));     // 12

ArrayList

as

class ClassA { }
class ClassB { }

class MainClass
{
    static void Main()
    {
        object[] objArray = new object[6];
        objArray[0] = new ClassA();
        objArray[1] = new ClassB();
        objArray[2] = "hello";
        objArray[3] = 123;
        objArray[4] = 123.4;
        objArray[5] = null;

        for (int i = 0; i < objArray.Length; ++i)
        {
            string s = objArray[i] as string;
            Console.Write("{0}:", i);
            if (s != null)
            {
                Console.WriteLine("'" + s + "'");
            }
            else
            {
                Console.WriteLine("not a string");
            }
        }
    }
}
/*
  Output:
  0:not a string
  1:not a string
  2:'hello'
  3:not a string
  4:not a string
  5:not a string
*/

Attributes

[AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
public class SortOrderAttribute : Attribute
{
    public int SortOrder { get; set; }

    public SortOrderAttribute(int sortOrder)
    {
        this.SortOrder = sortOrder;
    }
}

[SortOrder(23)]
public class MyClass
{
    public MyClass()
    {
    }
}

public class MyInvestigatorClass
{
    public void InvestigateTheAttribute()
    {
        Type type = typeof(MyClass);
        object[] attributes = type.GetCustomAttributes(typeof(SortOrderAttribute), true);
        SortOrderAttribute attribute = attributes[0] as SortOrderAttribute;
        int sortOrder = attribute.SortOrder;
        // Do something with sortOrder
    }
}

const

delegate

// Declare delegate -- defines required signature:
delegate double MathAction(double num);

class DelegateTest
{
    // Regular method that matches signature:
    static double Double(double input)
    {
        return input * 2;
    }

    static void Main()
    {
        // Instantiate delegate with named method:
        MathAction ma = Double;

        // Invoke delegate ma:
        double multByTwo = ma(4.5);
        Console.WriteLine("multByTwo: {0}", multByTwo);

        // Instantiate delegate with anonymous method:
        MathAction ma2 = delegate(double input)
            {
                return input * input;
            };

        double square = ma2(5);
        Console.WriteLine("square: {0}", square);

        // Instantiate delegate with lambda expression
        MathAction ma3 = s => s * s * s;
        double cube = ma3(4.375);

        Console.WriteLine("cube: {0}", cube);
    }
    // Output:
    // multByTwo: 9
    // square: 25
    // cube: 83.740234375
}

event

using System;

class Test
{
    public event EventHandler MyEvent
    {
        add
        {
            Console.WriteLine ("add operation");
        }

        remove
        {
            Console.WriteLine ("remove operation");
        }
    }

    static void Main()
    {
        Test t = new Test();

        t.MyEvent += new EventHandler (t.DoNothing);
        t.MyEvent -= null;
    }

    void DoNothing (object sender, EventArgs e)
    {
    }
}

foreach

int[,] numbers2D = new int[3, 2] { { 9, 99 }, { 3, 33 }, { 5, 55 } };
// Or use the short form:
// int[,] numbers2D = { { 9, 99 }, { 3, 33 }, { 5, 55 } };

foreach (int i in numbers2D)
 {
     System.Console.Write("{0} ", i);
 }
// Output: 9 99 3 33 5 55

Int32, Int64

Lambda Expressions

(x, y) => x == y;
(int x, string s) => s.Length > x;
() => SomeMethod();

delegate void TestDelegate(string s);
TestDelegate del = n => { string s = n + " World";
                          Console.WriteLine(s); };

// Many C# developers use _ to indicate that the parameter isn't going to be used
_ => 10

List<T>

List<string> colors = new List<string>();
colors.Add("Red");
colors.Add("Blue");
colors.Add("Green");

colors.Count;


foreach (string color in colors)
{
    MessageBox.Show(color);
}

for (int i = 0; i < colors.Count; i++)
{
    MessageBox.Show(colors[i]);
}

colors.Insert(1, "violet");
colors.Sort();
colors.Remove("violet");


if (colors.Contains("Blue"))
{
    MessageBox.Show("Blue color exist in the list");
}

string[] strArr = new string[3];
strArr[0] = "Red";
strArr[1] = "Blue";
strArr[2] = "Green";
//here to copy array to List
List<string> arrlist = new List<string>(strArr);

string combindedString = string.Join(",", colors);

string[] arr = colors.ToArray();

arrlist.Clear ();

Method Parameter Keywords

params

public class MyClass
{
    public static void UseParams(params int[] list)
    {
        for (int i = 0; i < list.Length; i++)
        {
            Console.Write(list[i] + " ");
        }
        Console.WriteLine();
    }

    public static void UseParams2(params object[] list)
    {
        for (int i = 0; i < list.Length; i++)
        {
            Console.Write(list[i] + " ");
        }
        Console.WriteLine();
    }

    static void Main()
    {
        UseParams(1, 2, 3, 4);
        UseParams2(1, 'a', "test");
        UseParams2();

        int[] myIntArray = { 5, 6, 7, 8, 9 };
        UseParams(myIntArray);

        object[] myObjArray = { 2, 'b', "test", "again" };
        UseParams2(myObjArray);

        // The following call does not cause an error, but the entire
        // integer array becomes the first element of the params array.
        UseParams2(myIntArray);
    }
}
/*
Output:
    1 2 3 4
    1 a test

    5 6 7 8 9
    2 b test again
    System.Int32[]
*/

ref

class RefExample
{
    static void Method(ref int i)
    {
        i = i + 44;
    }

    static void Main()
    {
        int val = 1;
        Method(ref val); // call with 'ref'
        Console.WriteLine(val);
        // Output: 45
    }
}


class CS0663_Example
{
    // Compiler error CS0663: "Cannot define overloaded
    // methods that differ only on ref and out".
    public void SampleMethod(out int i) { }
    public void SampleMethod(ref int i) { }
}

class RefOverloadExample
 {
     // However, overloading can be done
     // when one method has a ref or out parameter and the other has a value parameter
     public void SampleMethod(int i) { }
     public void SampleMethod(ref int i) { }
}

out

class OutReturnExample
{
    static void Method(out int i, out string s1, out string s2)
    {
        i = 44;
        s1 = "I've been returned";
        s2 = null;
    }

    static void Main()
    {
        int value;
        string str1, str2;
        Method(out value, out str1, out str2);
        // value is now 44
        // str1 is now "I've been returned"
        // str2 is (still) null;
    }
}

Named and Optional Arguments

namespace OptionalNamespace
{
    class OptionalExample
    {
        static void Main(string[] args)
        {
            ExampleClass anExample = new ExampleClass();
            anExample.ExampleMethod(1, "One", 1);
            anExample.ExampleMethod(2, "Two");
            anExample.ExampleMethod(3);

            ExampleClass anotherExample = new ExampleClass("Provided name");
            anotherExample.ExampleMethod(1, "One", 1);
            anotherExample.ExampleMethod(2, "Two");
            anotherExample.ExampleMethod(3);

            // You can use a named parameter
            anExample.ExampleMethod(3, optionalint: 4);
        }
    }

    class ExampleClass
    {
        private string _name;

        public ExampleClass(string name = "Default name")
        {
            _name = name;
        }

        public void ExampleMethod(int required, string optionalstr = "default string", int optionalint = 10)
        {
            Console.WriteLine("{0}: {1}, {2}, and {3}.", _name, required, optionalstr, optionalint);
        }
    }

    // The output from this example is the following:
    // Default name: 1, One, and 1.
    // Default name: 2, Two, and 10.
    // Default name: 3, default string, and 10.
    // Provided name: 1, One, and 1.
    // Provided name: 2, Two, and 10.
    // Provided name: 3, default string, and 10.
    // Default name: 3, default string, and 4.
}

null

// Traditional null check
var handler = this.PropertyChanged;
if (handler != null)
    handler(…)

// equivalent to, and thread-safe thanks to compiler
PropertyChanged?.Invoke(e)
int? length = customers?.Length; // null if customers is null
Customer first = customers?[0];  // null if customers is null
int? count = customers?[0]?.Orders?.Count();  // null if customers, the first customer, or Orders is null
// The ?? operator is called the null-coalescing operator.
// It returns the left-hand operand if the operand is not null;
// otherwise it returns the right hand operand.

int? x = null;
// Set y to the value of x if x is NOT null; otherwise,
// if x = null, set y to -1.
int y = x ?? -1;

Nullable<T>

Properties

public class Date
{
    private int month = 7;  // Backing store

    public int Month
    {
        get
        {
            return month;
        }
        set
        {
            if ((value > 0) && (value < 13))
            {
                month = value;
            }
        }
    }
  }
// From C# 3.0
// Auto-Impl Properties for trivial get and set
public double TotalPurchases { get; set; }
public string Name { get; set; }
public int CustomerID { get; set; }

// From C# 6.0
public string FirstName { get; set; } = "Jane";

PropertyInfo

var ps = typeof(DevSettings).GetProperties();
foreach (PropertyInfo p in ps)
{
    if (p.PropertyType == typeof(int))
    {
        // First parameter fo Get/SetValue is 'obj'
        // Using 'null' here because the property is static;
        int value = (int)p.GetValue(null, null);
        p.SetValue(null, value + 1, null);
    }
}

readonly

Also as a consequence of const requiring a literal, it's inherently static while a readonly field can be either static or instance.

class Age
{
    readonly int _year;
    Age(int year)
    {
        _year = year;
    }

    void ChangeYear()
    {
        //_year = 1967; // Compile error if uncommented.
    }
  }

Static Class and Static Class Members

public class Automobile
{
    public static int NumberOfWheels = 4;
    public static int SizeOfGasTank
    {
        get
        {
            return 15;
        }
    }
    public static void Drive() { }
    public static event EventType RunOutOfGas;

    // Other non-static fields and properties...
}
class SimpleClass
{
    // Static variable that must be initialized at run time.
    static readonly long baseline;

    // Static constructor is called at most one time, before any
    // instance constructor is invoked or member is accessed.
    static SimpleClass()
    {
        baseline = DateTime.Now.Ticks;
    }
  }

string

string is an alias in C# for System.String. So technically, there is no difference. It's like int vs. System.Int32.

this

public Employee(string name, string alias)
{
    // Use this to qualify the fields, name and alias:
    this.name = name;
    this.alias = alias;
}

CalcTax(this);

public int this[int param]
{
    get { return array[param]; }
    set { array[param] = value; }
}

ToString

float score = 100.12345;
Debug.Log(score.ToString("F2"));  # Fixed point, prints "100.12"

typeof

System.Type type = typeof(int);

int i = 0;
System.Type type = i.GetType();  // Get runtime type

// Compare just like any other values
typeField == typeof(string);
typeField == typeof(DateTime);

using

// To allow the use of types in a namespace so that you do not have to qualify
using System.Text;

// To allow you to access static members of a type without having to qualify
using static System.Math;

// To create an alias for a namespace or a type. This is called a using alias directive
using Project = PC.MyCompany.Project;

Compiler Options

define

// preprocessor_define.cs
// compile with: /define:xx
// or uncomment the next line
// #define xx
using System;
public class Test
{
    public static void Main()
    {
        #if (xx)
            Console.WriteLine("xx defined");
        #else
            Console.WriteLine("xx not defined");
        #endif
    }
}

Details

Value Types and Reference Types

abstract, virtual, override, sealed

C# Coding Conventions

var currentPerformanceCounterCategory = new System.Diagnostics.
    PerformanceCounterCategory();

// Use the + operator to concatenate short strings, as shown in the following code.
string displayName = nameList[n].LastName + ", " + nameList[n].FirstName;

// To append strings in loops, especially when you are working with large amounts of text, use a StringBuilder object.
var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala";
var manyPhrases = new StringBuilder();
for (var i = 0; i < 10000; i++)
 {
     manyPhrases.Append(phrase);
}


// Use implicit typing for local variables when the type of the variable is obvious from the right side of the assignment,
// or when the precise type is not important.
var var1 = "This is clearly a string.";
var var2 = 27;
var var3 = Convert.ToInt32(Console.ReadLine());


// Preferred syntax. Note that you cannot use var here instead of string[].
string[] vowels1 = { "a", "e", "i", "o", "u" };
// If you use explicit instantiation, you can use var.
var vowels2 = new string[] { "a", "e", "i", "o", "u" };
// If you specify an array size, you must initialize the elements one at a time.
var vowels3 = new string[5];
vowels3[0] = "a";
vowels3[1] = "e";


// This try-finally statement only calls Dispose in the finally block.
Font font1 = new Font("Arial", 10.0f);
try
{
     byte charset = font1.GdiCharSet;
}
finally
{
     if (font1 != null)
     {
         ((IDisposable)font1).Dispose();
     }
}
// You can do the same thing with a using statement.
using (Font font2 = new Font("Arial", 10.0f))
{
     byte charset = font2.GdiCharSet;
}


Console.Write("Enter a dividend: ");
var dividend = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter a divisor: ");
var divisor = Convert.ToInt32(Console.ReadLine());
// If the divisor is 0, the second clause in the following condition
// causes a run-time error. The && operator short circuits when the
// first expression is false. That is, it does not evaluate the
// second expression. The & operator evaluates both, and causes 
// a run-time error when divisor is 0.
if ((divisor != 0) && (dividend / divisor > 0))
 {
     Console.WriteLine("Quotient: {0}", dividend / divisor);
 }
 else
 {
     Console.WriteLine("Attempted division by 0 ends up here.");
}


// Call static members by using the class name: ClassName.StaticMember.
// This practice makes code more readable by making static access clear.
// Do not qualify a static member defined in a base class with the name of a derived class.
// While that code compiles, the code readability is misleading, and the code may break in the future
// if you add a static member with the same name to the derived class.

Creating delegates manually vs using Action/Func delegates

private delegate double ChangeListAction(string param1, int number);
private Func<string, int, double> ChangeListAction;
private Action<string,int> ChangeListAction;

Use Cases

Can I make local vairalbes constant?

In short, No. Because:

Can I handle inputs in FixedUpdate?

General Rule:

Gaussian Random

// Box–Muller transform
// https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
public static float GaussianRandom(float mu, float sigma)
{
          float u1 = Random.Range(0.0f, 1.0f);
          float u2 = Random.Range(0.0f, 1.0f);
          float z0 = Mathf.Sqrt(-2.0f * Mathf.Log(u1)) * Mathf.Cos((2.0f * Mathf.PI) * u2);
          return (mu + sigma * z0);
      }

General Structure of a C# Program

// A skeleton of a C# program 
using System;
namespace YourNamespace
{
    class YourClass
    {
    }

    struct YourStruct
    {
    }

    interface IYourInterface 
    {
    }

    delegate int YourDelegate();

    enum YourEnum 
    {
    }

    namespace YourNestedNamespace
    {
        struct YourStruct 
        {
        }
    }

    class YourMainClass
    {
        static void Main(string[] args) 
        {
            //Your program starts here...
        }
    }
}

Increment operator: Post vs Pre?

Main Method

static void Main()
{
    //...
}
static int Main()
{
    //...
    return 0;
}
static void Main(string[] args)
{
    //...
}
static int Main(string[] args)
{
    //...
    return 0;
}

Get property name inside setter

using System.Reflection

public static int Dummy {
    get {
        var propertyName = MethodBase.GetCurrentMethod().Name.Substring(4);
        Console.WriteLine(propertyName);
        return 0;
    }
}

Use string.Substring(4) to remoe get_ or set_:

Invoke a method with Reflection


IEnumerator Phase(int n)
{
    string name = string.Format("Phase{0:00}", n);
    BindingFlags bf = BindingFlags.Instance | BindingFlags.NonPublic;
    MethodInfo m = typeof(Master).GetMethod(name, bf);
    if (m == null)
    {
        m = typeof(Master).GetMethod("PhaseXX", bf);
    }
    return (IEnumerator)m.Invoke(this, new object[] {Jukebox.Tempo});
}