This document is a quick guide of F #object oriented programming constructs and their equivalent in C#, where applicable. For more information on F#, please visit http://www.fsharp.net for documentation, videos, and samples.
Language Feature
F#
C#
Classes with properties and default constructor
type Vector(x : float, y : float) =
member this.X = x
member this.Y = y
// Usage:
let v = Vector(10., 10.)
let x = v.X
let y = v.Y
public class Vector
{
double x;
double y;
public Vector(double x, double y)
this.x = x;
this.y = y;
}
public double X
get { return this.x; }
public double Y
get { return this.y; }
Vector v = new Vector(10, 10);
double x = v.X;
double y = v.Y;
Structs with properties
[<Struct>]
public struct Vector
Multiple constructors
new(v : Vector, s) = Vector(v.X * s, v.Y * s)
let w = new Vector(v, 0.5)
public Vector(Vector v, double s) :
this(v.x * s, v.y * s)
Vector w = new Vector(v, 0.5);
Member functions
type Vector(x, y) =
member this.Scale(s) =
Vector(x * s, y * s)
let v2 = v.Scale(0.5)
public double Scale(double s)
return new Vector(this.x * s,
this.y * s);
Vector v2 = v.Scale(0.5);
Operators
static member (*) (a : Vector, b : Vector) =
a.X * b.X + a.Y + b.Y
let x = Vector(2., 2.)
let y = Vector(3., 3.)
let dp = x * y
public static double operator * (
Vector v1, Vector v2)
return v1.x * v2.x + v1.y * v2.y;
Vector x = new Vector(2, 2);
Vector y = new Vector(3, 3);
double dp = x * y;
Static members and properties
static member Dot(a : Vector, b : Vector) =
static member NormX = Vector(1., 0.)
let y = Vector.NormX
let dp = Vector.Dot(x, y)
public static double Dot(Vector v1,
Vector v2)
public static Vector NormX
get { return new Vector(1, 0); }
Vector y = Vector.NormX;
double dp = Vector.Dot(x, y);
Class properties that use let value computations in the constructor
let mag = sqrt(x * x + y * y)
let rad = if x = 0. && y = 0. then
0.
else if x >= 0. then
asin(y / mag)
else
(-1. * asin(y / mag)) +
Math.PI
member this.Mag = mag
member this.Rad = rad
let mag = v.Mag
let rad = v.Rad
double mag = 0.0;
double rad = 0.0;
this.mag = Math.Sqrt(x * x + y * y);
if (x == 0.0 && y == 0.0) rad = 0.0;
else if (x >= 0.0)
rad = Math.Asin(y / mag);
rad = (-1.0 * Math.Asin(y / mag)) + Math.PI;
public double Mag
get { return this.mag; }
public double Rad
get { return this.rad; }
double mag = v.Mag;
double rad = v.Rad;
Class members that use private function values
let rotate a =
let x' = x * cos a – y * sin a
let y' = y * sin a + y * cos a
new Vector(x', y')
member this.RotateByDegrees(d) =
rotate (d * Math.PI / 180.)
member this.RotateByRadians(r) =
rotate r
let v = Vector(10., 0.)
let x = v.RotateByDegrees(90.)
let y = v.RotateByRadians(Math.PI / 6.)
double x = 0.0;
double y = 0.0;
Vector rotate(double a)
double xx = this.x * Math.Cos(a) –
this.y * Math.Sin(a);
double yy = this.y * Math.Sin(a) +
this.y * Math.Cos(a);
return new Vector(xx, yy);
public Vector RotateByDegrees(double d)
return rotate(d * Math.PI / 180);
public Vector RotateByRadians(double r)
return rotate(r);
Vector x = v.RotateByDegrees(90.0);
Vector y = v.RotateByRadians(Math.PI / 6.0);
Overloading members
type Car() =
member this.Drive() =
this.Drive(10)
()
member this.Drive(mph : int) =
// Do something
let c = Car()
c.Drive()
c.Drive(10)
public class Car
public void Drive()
Drive(10);
public void Drive(int mph)
Car c = new Car();
c.Drive();
c.Drive(10);
Mutable fields in a class with get/set properties
type MutableVector(x : float, y : float) =
let mutable cx = x
let mutable cy = y
member this.X with get() = cx and
set(v) = cx <- v
member this.Y with get() = cy and
set(v) = cy <- v
member this.Length = sqrt(x * x + y * y)
let v = MutableVector(2., 2.)
let len1 = v.Length
v.X <- 3.
v.Y <- 3.
let len2 = v.Length
public class MutableVector
public MutableVector(double x, double y)
this.X = x;
this.Y = y;
public double X { get; set; }
public double Y { get; set; }
public double Length
get { return Math.Sqrt(
this.X * this.X +
this.Y * this.Y); }
MutableVector v = new MutableVector(2.0, 2.0);
double len1 = v.Length;
v.X = 3.0;
v.Y = 3.0;
double len2 = v.Length;
Generic classes and function arguments
type Factory<'T>(f : unit -> 'T) =
member this.Create() =
f()
let strings = Factory<string>(
fun () -> "Hello!")
let res = strings.Create()
let ints = Factory<int>(fun () -> 10)
let res = ints.Create()
public class Factory<T>
Func<T> creator;
public Factory(Func<T> f)
this.creator = f;
public T Create()
return this.creator();
Factory<string> strings = new
Factory<string>(() => "Hello");
string res1 = strings.Create();
Factory<int> ints = new Factory<int>(() => 10);
int res2 = ints.Create();
Generic classes and methods
type Container<'T>(a : 'T) =
member this.Convert<'U>(f : 'T -> 'U) =
f a
let c = new Container<int>(10)
let b = c.Convert(fun a -> a.ToString())
public class Container<T>
private T value;
public Container(T t)
this.value = t;
public U Convert<U>(Func<T, U> f)
return f(this.value);
Container<int> c = new Container<int>(10);
string result = c.Convert(n => n.ToString());
Extension methods
type List<'T> with
member this.MyExtensionMethod() =
this |> Seq.map (fun a -> a.ToString())
let c = [1; 2; 3]
let d = c.MyExtensionMethod()
public static class ExtensionMethods
public static IEnumerable<string>
MyExtensionMethod<T>(this List<T> a)
return a.Select(s => s.ToString());
List<int> l = new List<int> { 1, 2, 3 };
IEnumerable<string> res =
l.MyExtensionMethod();
Extension properties
member this.MyExtensionProp =
let d = c.MyExtensionProp
N/A. C# does not support this feature.
Indexers
type Table() =
member this.Item
with get(key : string) = int key
let tab = Table()
let x = tab.["10"]
let y = tab.["12"]
public class Table
public int this[string key]
get { return Convert.ToInt32(key); }
Table tab = new Table();
int x = tab["10"];
int y = tab["12"];
Indexed Properties
member this.Values
member this.MultipleValues
with get(key1, key2) = key1 + key2
let x = tab.Values("10")
let y = tab.Values("12")
let a = tab.MultipleValues(10, 5)
Abstract classes
[<AbstractClass>]
type Shape() =
abstract Name : string with get
abstract Scale : float -> Shape
public abstract class Shape
public abstract string Name { get; }
public abstract Shape Scale(double scale);
Derive from a base class and overriding base methods with generics
type Shape<'T>() =
abstract Scale : float -> 'T
type Vector(angle, mag) =
inherit Shape<Vector>()
member this.Angle = angle
member this.Mag = makg
override this.Name = "Vector"
override this.Scale(factor) =
Vector(angle, mag * factor)
let v = Vector(45., 10.)
public abstract class Shape<T>
public abstract T Scale(double scale);
public class Vector : Shape<Vector>
double angle;
double mag;
public double Angle {get{return angle;}}
public double Mag {get{return mag;}}
public Vector(double angle, double mag)
this.angle = angle;
this.mag = mag;
public override string Name
get { return "Vector"; }
public override Vector Scale(double scale)
return new Vector(this.Angle,
this.Mag * scale);
Vector v = new Vector(45, 10);
Calling a base class method
type Animal() =
member this.Rest() =
// Rest for the animal
type Dog() =
inherit Animal()
member this.Run() =
// Run
base.Rest()
let brian = new Dog()
brian.Run()
public class Animal
public void Rest()
public class Dog : Animal
public void Run()
base.Rest();
Dog brian = new Dog();
brian.Run();
Implementing an interface
type IVector =
abstract Mag : double with get
abstract Scale : float -> IVector
interface IVector with
member this.Mag = sqrt(x * x + y * y)
Vector(x * s, y * s) :> IVector
let v = new Vector(1., 2.) :> IVector
let w = v.Scale(0.5)
let mag = w.Mag
interface IVector
double Mag { get; }
IVector Scale(double s);
class Vector : IVector
get { return Math.Sqrt( this.x * this.x +
this.y * this.y); }
public IVector Scale(double s)
IVector v = new Vector(1, 2);
IVector w = v.Scale(0.5);
double mag = w.Mag;
Implementing an interface with object expressions
type ICustomer =
abstract Age : int with get
let CreateCustomer name age =
{ new ICustomer with
member this.Name = name
member this.Age = age
let c = CreateCustomer "Snoopy" 16
let d = CreateCustomer "Garfield" 5
N/A. C# does not support creating object expressions.
Events
type BarkArgs(msg:string) =
inherit EventArgs()
member this.Message = msg
type BarkDelegate =
delegate of obj * BarkArgs -> unit
let ev = new Event<BarkDelegate, BarkArgs>()
member this.Bark(msg) =
ev.Trigger(this, new BarkArgs(msg))
[<CLIEvent>]
member this.OnBark = ev.Publish
let snoopy = new Dog()
snoopy.OnBark.Add(
fun ba -> printfn "%s" (ba.Message))
snoopy.Bark("Hello")
public class BarkArgs : EventArgs
private string msg;
public BarkArgs(string msg)
this.msg = msg;
public string Message
get { return this.msg; }
public delegate void BarkDelegate(
Object sender, BarkArgs args);
class Dog
public event BarkDelegate OnBark;
public void Bark(string msg)
OnBark(this, new BarkArgs(msg));
Dog snoopy = new Dog();
snoopy.OnBark += new BarkDelegate(
(sender, msg) =>
Console.WriteLine(msg.Message));
snoopy.Bark("Hello");
Explicit class constructor
type Vector =
val mutable x : float
val mutable y : float
new() = {x = 0.; y = 0.}
let v = Vector()
v.x <- 10.
v.y <- 10.
Explicit public fields
type Vector() =
[<DefaultValue()>]
val mutable x : int
val mutable y : int
v.x <- 10
v.y <- 10
public int x;
public int y;
Vector v = new Vector();
v.x = 10;
v.y = 10;
Explicit struct definition
val mutable public x : int
val mutable public y : int
let mutable v = Vector()