Enterprise development (in .NET), Day 3
Introduction to C#
Andrey Shchekin http://ashmind.com Sankt-Petersburg, 2009
Images © Mattahan Productions, Inc | http://mattahan.deviantart.com/ | http://mattahan.insocada.com/
C# 1.0
OOP in C#/.NET
Everything is an object:
string answer = 42.ToString();
Every function belongs somewhere:
Math.Sin(1.0)
Namespaces
namespace AshMind.Web.UI.Research { public class Repeater { … } }
Usage
using AshMind.Web.UI.Research;
Namespaces are just logical (naming) blocks. 1 assembly can have any namespaces 1 namespace can be in many assemblies
Data Types
Data Types
Value Types
In stack Created faster Always copied Short-lived No inheritance No null
Reference Types
In heap Created slower Always referenced Garbage collected Allow inheritance Allow null
object (System.Object)
Common methods: GetType() Equals(object obj) GetHashCode() ToString()
Numeric Types
Integral
byte short int long 8bit 16bit 32bit 64bit
Floating-point
float double
System.IntPtr = native int
String Types 1
String types: string, char.
string value = "single-line value"; string other = @" multi-line string "; char symbol = 'x';
All strings are Unicode.
String Types 2
Strings are immutable.
string name = "Gordon"; string copy = name; name += " Freeman"; Console.WriteLine("Name is: {0}", copy);
Use StringBuilder for lots of changes.
Structs
public struct Point { public int X { ... } public int Y { ... } } Point point = new Point(); point.X = 5; ...
All structs inherit System.ValueType.
Enums
public enum ConsoleColor { Black, Red, Green, ... }
ConsoleColor color = ConsoleColor.Black; ...
All enums inherit System.Enum.
Type Casting
()
MyClass myClass = (MyClass)obj; myClass.DoSomething();
as
MyClass myClass = obj as MyClass; if (myClass != null) myClass.DoSomething();
is
if (obj is MyClass) (obj as MyClass).DoSomething();
Type Conversion
string value = "5"; int number = (int)value; -- error !
string value = "5"; int parsed = int.Parse(value);
Classes
Methods
public class Program { public static void Main(string[] args) { Console.WriteLine("Good bye, world!"); DestroyWorld(); } }
All methods belong somewhere (mostly classes).
Fields
public class Developer { private string name; public void Rename(string newName) { this.name = newName; } } Developer developer = new Developer(); developer.Rename("Freeman");
Properties
public class Developer { private string name; public string Name { get { return this.name; } set { this.name = value; } } }
Developer developer = new Developer(); developer.Name = "Freeman";
Events
public class Developer { public event EventHandler NameChanged;
private string name; public string Name { get { return this.name; } set { this.name = value; if (this.NameChanged != null) this.NameChanged(this, EventArgs.Empty); }
}
} Developer developer = new Developer(); developer.NameChanged += developer_NameChanged;
Operators
public struct Complex { public double Re { ... } public double Im { ... } public static Complex operator+(Complex return new Complex( left.Re + right.Re, left.Im + right.Im ); } public static Complex operator+(Complex return new Complex( left.Re + right, left.Im ); } }
left, Complex right)
{
left, double right)
{
Inheritance
public class Developer { /* ... */ public virtual void DoWork(); }
public sealed class TechLead : Developer { private string name; public TechLead(string name) : base(name) { this.name = name; } public override void DoWork() { Console.WriteLine("Researching …"); } }
Interfaces
Allow class to define small responsibilities.
public interface IComparable { int CompareTo(IComparable other); }
Abstract class contract from inheritance.
public interface IList { ... } IList items = new string[5];
Other stuff
Naming conventions
Pascal Case: Classes Methods Properties Constants camel Case: parameters fields Prefixes: Classes Interfaces class TopManager void Manage(); double Salary { … } const int MaxValue;
int Sum(int first, int second); double salary;
I
class Developer interface IComparable
Exceptions
try { this.SaveTo(writer); } catch (IOException ex) { this.Log(ex); throw new SaveException("…", ex); } catch (Exception ex) { this.Log(ex); throw; } finally { writer.Close(); }
Throwing without argument preserves stack.
Foreach/IEnumerable
foreach (Developer developer in developers) { this.Hire(developer); }
IEnumerator enumerator = developers.GetEnumerator(); while (enumerator.MoveNext()) { this.Hire((Developer)enumerator.Current); }
Using/IDisposable
using (XmlWriter writer = XmlWriter.Create(file)) { this.SaveTo(writer); }
XmlWriter writer = XmlWriter.Create(file) try { this.SaveTo(writer); } finally { writer.Dispose(); }
Attributes
public class RequiredAttribute : Attribute {} public class Developer { private string name; [Required, MaxLength(60)] public string Name { get { return this.name; } set { this.name = value; } } } Attributes do not do anything, you have to check for them.
C# 2.0
Generics
List urls = new List(); urls.Add("http://www.google.com"); urls.Add("http://www.habr.ru"); urls.Add(5); return urls; Generics are supported on Types class List Methods void Save();
IEnumerable/Yield
IEnumerable Range(int start, int length) { for (int i = start; i (T value);
Using method
private bool NameStartsWithA(Developer developer) { return developer.Name.StartsWith("A"); }
Developer developer = developers.FindFirst(NameStartsWithA);
Using anonymous delegate
Developer developer = developers.FindFirst(delegate(Developer d){ return d.Name.StartsWith("A"); });
Nullable types
public int? CalculateAge(Person person) { if (person.Birthday == null) return null; return DateTime.Now.Year – person.Birthday.Year; }
?? (coalesce)
int age = CalculateAge(person) ?? -1;
C# 3.0
Automatic properties
public class Developer { public string Name { get; set; } } Developer developer = new Developer(); developer.Name = "Freeman";
Implicit variables
Before
List developers = new List(); Manager manager = new Manager() foreach (Developer developer in developers) { manager.Hire(developer); }
After
var developers = new List(); var manager = new Manager()
foreach (var developer in developers) { manager.Hire(developer); }
Object initializers
Before
Order order = new Order(); order.TotalCost = cost; order.Approved = approved; order.Special.Name = nameOfSpecial; return order;
After
return new Order { TotalCost = cost, Approved = approved, Special = { Name = nameOfSpecial } }
Collection initializers
Before
List urls = new List(); urls.Add("http://www.google.com"); urls.Add("http://www.habr.ru"); return urls;
After
return new List { "http://www.google.com", "http://www.habr.ru", };
Extension methods 1
public static class ListExtensions { public static void AddRange( this IList list, IEnumerable items ) { foreach (var item in items) { list.Add(item); } } } … urls.AddRange(newUrls); // urls : IList
Extension methods 2
var date = 5.Minutes().Ago();
5.Times(Console.WriteLine)
New delegate syntax
// C# 2.0 Developer freeman = developers.Find( delegate(Developer developer) { return developer.LastName == “Freeman"; }; );
// C# 3.0: λ-expression Developer freeman = developers.Find( d => d.LastName == "Freeman" );
Before LINQ
var newMessagesToPrint = new List(); this.SortByDateDescending(messages); foreach (var message in messages) { if (!message.IsUnread) continue; newMessagesForPrint.Add( message.FormatForPrint() ); }
LINQ
var newMessagesToPrint = from message in messages where message.IsUnread orderby message.Date descending select message.FormatForPrint();
var newMessagesToPrint = messages .Where(m => m.IsUnread) .OrderByDescending(m => m.Date) .Select(m => m.FormatForPrint())
Questions