Monthly Archives: February 2014
migration C#, Java, C++ (day 4)
Today we translate some basics of threading and locking. For the ones, who follow the C# hardcore posts, I will cover the C# side in more detail on Tuesday.
Further down I also cover operator overloading today.
Some background info:
Deadlocks
WaitOne
There are no direct equivalents in C++ for the C# lock keyword, the Monitor class and Semaphores unless you are using the .Net Framework on the C++ side. This is clearly not what you want to do. The speed advantage of C++ would end in smoke.
Mutexes do exist for both C# and C++. You have to get used to using Mutexes in C++. They are hardly used in C#, but found often in C++.
The C++ mutex is not the same as the C# Mutex. This is as confusing as using a C# List and think it would be similar to a C++ list.
The C++ mutex is (depite its name) much closer to the C# Monitor class. It definitely is not as public as the C# Mutex, which is known to each process across the entire computer system.
Java looks quite retarded today. We already know that Java does not support pointers. Today it becomes even worse. There is no C# type mutex and no operator overloading.
Lock, Monitor, Semaphore
public void DoSomething() { Console.WriteLine("Good night my dear thread " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(2000); } // object lAnyObject2 = new object(); public void LockUsage() { lock (lAnyObject2) { DoSomething(); } } // object lAnyObject1 = new object(); public void MonitorUsage() { bool lLocked = false; try { Monitor.Enter(lAnyObject1, ref lLocked); // using System.Threading; DoSomething(); } finally { if (lLocked) Monitor.Exit(lAnyObject1); } } // // Limits the number of threads that can access a resource or pool of resources concurrently. private static Semaphore _Semaphore = new Semaphore(3, 3); // three objects allowed to access concurrently public void SemaphoreUsage() { bool lLocked = false; try { lLocked = _Semaphore.WaitOne(); DoSomething(); } finally { if (lLocked) _Semaphore.Release(); } } //
public final void DoSomething() { System.out.println("Good night my dear thread " + Thread.currentThread().getId()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } private Object lAnyObject2 = new Object(); public final void LockUsage() { synchronized (lAnyObject2) { DoSomething(); } } // Limits the number of threads that can access a resource or pool of resources concurrently. private static java.util.concurrent.Semaphore _Semaphore = new java.util.concurrent.Semaphore(3); // three objects allowed to access concurrently public final void SemaphoreUsage() { try { _Semaphore.acquire(); DoSomething(); } catch (InterruptedException e) { e.printStackTrace(); } finally { _Semaphore.release(); } }
Mutex
public void DoSomething() { Console.WriteLine("Good night my dear thread " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(2000); } // private const string cMutexName = "MyMutex"; private static Mutex _Mutex = new Mutex(false, cMutexName); // known by every process public void MutexUsage() { bool lLocked = false; try { // optional complexity: access rights //bool lNewCreation; //MutexSecurity lSecurity = new MutexSecurity(); //SecurityIdentifier lId = new SecurityIdentifier(WellKnownSidType.WorldSid, null); //MutexRights lRights = MutexRights.Synchronize | MutexRights.Modify; //lSecurity.AddAccessRule(new MutexAccessRule(lId, lRights, AccessControlType.Allow)); //_Mutex = new Mutex(false, cMutexName, out lNewCreation, lSecurity); //MutexSecurity lReverse = _Mutex.GetAccessControl(); lLocked = _Mutex.WaitOne(2000); // You can the option to set a time limit. Here 2000 milliseconds. if (!lLocked) { Console.WriteLine("Try again later. Mutex is used by another process or thread."); } DoSomething(); } finally { if (lLocked == true) _Mutex.ReleaseMutex(); } } //
// no mutexes available // use the synchronized block
void DoSomething() { cout << "Good night my dear thread " << this_thread::get_id() << endl; this_thread::sleep_for(chrono::milliseconds(2000)); } mutex _Mutex; void MutexUsage(){ _Mutex.lock(); try { DoSomething(); } catch (string e){ _Mutex.unlock(); throw e; } _Mutex.unlock(); } mutex _Mutex2; void MultipleMutexUsage(){ int x = try_lock(_Mutex, _Mutex2); if (x == -1) { DoSomething(); _Mutex.unlock(); _Mutex2.unlock(); } else cout << "failed to obtain lock for " << (x ? "_Mutex" : "_Mutex2") << endl; } void MutexUsage_For_Forgetful_People(){ lock_guard<mutex> guard(mutex); DoSomething(); } // auto unlocks here
operator overloading
public class myClass { // this class is not thread safe int[] Values = { 1, 2, 3 }; public static myClass operator +(myClass a, myClass b) { int n = a.Values.Length; myClass lNewClass = new myClass(); for (int i = 0; i < n; i++) lNewClass.Values[i] = a.Values[i] + b.Values[i]; return lNewClass; } // public static double operator *(myClass a, myClass b) { int n = a.Values.Length; int lSum = 0; for (int i = 0; i < n; i++) lSum += a.Values[i] * b.Values[i]; return lSum; } // public static string operator +(string a, myClass b) { //return ">> " + a + b + "<<"; // WRONG! causes recursion return ">> " + a + b.ToString() + "<<"; } // // I will explanation this in my post on Tuesday 4 February 2014 // uncomment this and play with it (=>hardcore C#) //public static string operator +(myClass a, string b) { // //return ">> " + a + b + "<<"; // WRONG! causes recursion // return ">> " + a + b.ToString() + "<<"; //} // // becomes even more hardcore when you have two conflicting overloads public override string ToString() { return "Values: " + Values[0] + " " + Values[1] + " " + Values[2] + " "; } // } // class public static void test() { myClass a = new myClass(); myClass b = new myClass(); myClass c = a + b; double d = a * b; Console.WriteLine("(Sum) " + c); // ">> (Sum) Values: 2 4 6 <<" Console.WriteLine("(Sum) " + c.ToString()); // "(Sum) Values: 2 4 6" Console.WriteLine(c + " (Sum)"); // "Values: 2 4 6 (Sum)" Console.WriteLine(d); // 14 Console.ReadLine(); } //
// there is no operator overloading available in Java
#include <string> #include <iostream> #include <memory> using namespace std; namespace OperatorOverloading { class myClass { private: int *Values = new int[] { 1, 2, 3 }; public: myClass &operator + (const myClass &b); //const string operator + (const myClass &b); // not possible to distinguish by return type only const string myClass::operator + (int &i); myClass &operator + (const int &i); // this is possible 🙂 double operator *(const myClass &b); const string ToString(); }; // class myClass &myClass::operator + (const myClass &b) { myClass *lNewClass = new myClass(); for (int i = 0; i < 3; i++) lNewClass->Values[i] = Values[i] + b.Values[i]; return *lNewClass; } myClass &myClass::operator + (const int &i) { myClass *lNewClass = new myClass(); for (int i = 0; i < 3; i++) lNewClass->Values[i] = 3 + Values[i]; return *lNewClass; } const string myClass::operator + (int &i) { return ">> " + ToString() + " -- " + to_string(i) + "<<"; } // const string myClass::operator + (const myClass &b) {} not possible double myClass::operator *(const myClass &b) { int lSum = 0; for (int i = 0; i < 3; i++) lSum += (this->Values[i]) * (b.Values[i]); return lSum; } const string myClass::ToString() { string s1 = to_string(Values[0]); string s2 = to_string(Values[1]); string s3 = to_string(Values[2]); return "Values: " + s1 + " " + s2 + " " + s3; } } // namespace int main() { using namespace OperatorOverloading; myClass a, b; myClass c = a + b; cout << c.ToString() << endl; // Values: 2 4 6 double d = a * b; cout << d << endl; // 14 myClass e = a + 3; cout << c.ToString() << endl; // Values: 5 7 9 cin.get(); return 0; }
migration C#, Java, C++ (day 3)
Containers in C++ are like C# collections.
The sequential containers are vector, deque and list. The latter is by far the slowest one. List comes close to LinkedList in C#. Vector and deque are like Lists in C#.
Available Methods:
vector | deque | list | |
similar in C# | List | List | LinkedList |
front(), back() | yes | yes | yes |
push_back(), pop_back() | yes | yes | yes |
push_front(), pop_front() | no | yes | yes |
at(), operator [] | yes | yes | no |
#include <iostream> #include <string> #include <list> #include <algorithm> #include <vector> #include <deque> #include <map> #include <unordered_map> #include <set> #include <unordered_set> #include <memory>
LinkedList
LinkedList<string> lLinkedList = new LinkedList<string>(); LinkedListNode<string> lLast = lLinkedList.AddLast("Last"); LinkedListNode<string> lFirst = lLinkedList.AddFirst("First"); LinkedListNode<string> lMid = lLinkedList.AddAfter(lFirst, "Mid"); bool b1 = lLinkedList.Contains("Last"); LinkedListNode<string> lFind = lLinkedList.Find("Last"); lLinkedList.Remove("First"); lLinkedList.RemoveFirst(); lLinkedList.Remove(lLast); lLinkedList.Clear();
java.util.LinkedList<String> lLinkedList = new java.util.LinkedList<String>(); lLinkedList.addLast("Last"); lLinkedList.addFirst("First"); lLinkedList.add(1, "Mid"); boolean b1 = lLinkedList.contains("Last"); int lFind = lLinkedList.indexOf("Last"); //lLinkedList.remove(lFind); lLinkedList.remove("First"); lLinkedList.removeFirst(); lLinkedList.removeLast(); lLinkedList.clear();
list<string> lLinkedList = list<string>(); lLinkedList.push_back("Last"); lLinkedList.push_front("First"); list<string>::iterator lIterator = lLinkedList.begin(); lIterator++; lLinkedList.insert(lIterator, "Mid1"); lLinkedList.insert(lIterator, "Mid2"); cout << "List: " << endl; for (lIterator = lLinkedList.begin(); lIterator != lLinkedList.end(); lIterator++) cout << *lIterator << " "; //List: First Mid1 Mid2 Last lLinkedList.remove("First"); lLinkedList.pop_front(); lLinkedList.remove("Mid2"); cout << endl << endl << "List: " << endl; for (lIterator = lLinkedList.begin(); lIterator != lLinkedList.end(); lIterator++) cout << *lIterator << " "; //List: Last lLinkedList.clear();
List
List<string> lList = new List<string>(); lList.Add("First"); lList.AddRange(new string[] { "Mid1", "Last" }); bool b2 = lList.Contains("Mid1"); lList.Insert(2, "Mid2"); // First, Mid1, Mid2, Last lList.Reverse(); // Last, Mid2, Mid1, First lList.Sort(); // First, Last, Mid1, Mid2 string[] lStringArray = lList.ToArray(); lList.Clear();
java.util.ArrayList<String> lList = new java.util.ArrayList<String>(); lList.add("First"); lList.addAll(Arrays.asList("Mid1", "Last")); boolean b2 = lList.contains("Mid1"); // true lList.add(2, "Mid2"); // First, Mid1, Mid2, Last java.util.Collections.reverse(lList); // Last, Mid2, Mid1, First java.util.Collections.sort(lList); // First, Last, Mid1, Mid2 String[] lStringArray = lList.toArray(new String[0]); lList.clear();
inline bool MyDataSortPredicate(const string &s1, const string &s2) { return s1 < s2; } vector<string> lList = vector<string>(); lList.push_back("First"); string lArray[] {lList.front(), "Mid", "Last"}; lList.assign(lArray, lArray + 3); lList.push_back("VeryLast"); // First, Mid, Last, VeryLast reverse(lList.begin(), lList.end()); // VeryLast, Last, Mid, First sort(lList.begin(), lList.end(), MyDataSortPredicate); // First, Last, Mid, VeryLast string *lStringArray = lList.data(); lStringArray++; string lResult = lStringArray[1]; // Mid lList.clear(); deque<string> lList2 = deque<string>(); lList2.push_back("First"); string lArray2[] {lList2.front(), "Mid", "Last"}; lList2.assign(lArray2, lArray2 + 3); auto lIterator2 = lList2.end(); lIterator2--; lList2.emplace(lIterator2, "Mid2"); lList2.push_back("VeryLast"); // First, Mid, Mid2, Last, VeryLast reverse(lList2.begin(), lList2.end()); // VeryLast, Last, Mid2, Mid, First sort(lList2.begin(), lList2.end(), MyDataSortPredicate); // First, Last, Mid, Mid2, VeryLast lList2.clear();
Collections comparison
// key value pairs (no duplicate keys) Dictionary<string, string> lDictionary = new Dictionary<string, string>(); // uses a hashmap SortedDictionary<string, string> lSortedDictionary = new SortedDictionary<string, string>(); // uses a binary tree SortedList<string, string> lSortedList = new SortedList<string, string>(); // uses arrays // lists List<string> lList3 = new List<string>(); // duplicate entries allowed HashSet<string> lHashSet = new HashSet<string>(); // a List with no duplicates entries; behaves like a Dictionary with key==value SortedSet<string> lSortedSet = new SortedSet<string>(); // a sorted list with no duplicates; behaves like a SortedDictionary with key==value
// key value pairs (no duplicate keys) java.util.HashMap<String, String> lDictionary = new java.util.HashMap<String, String>(); java.util.TreeMap<String, String> lSortedDictionary = new java.util.TreeMap<String, String>(); // There is no such as a SortedList in Java // lists java.util.ArrayList<String> lList3 = new java.util.ArrayList<String>(); java.util.HashSet<String> lHashSet = new java.util.HashSet<String>(); java.util.TreeSet<String> lSortedSet = new java.util.TreeSet<String>();
// key value pairs (no duplicate keys) unordered_map<string, string> lDictionary = unordered_map<string, string>(); // uses a hashmap map<string, string> lSortedDictionary = map<string, string>(); // uses a binary tree // lSortedList = no equivalent // lists vector<string> lList2 = vector<string>(); // duplicate entries allowed unordered_set<string> lHashSet = unordered_set<string>(); // a List with no duplicates entries; behaves like a Dictionary with key==value set<string> lSortedSet = set<string>(); // a sorted list with no duplicates; behaves like a SortedDictionary with key==value
Threading
void f1() { Thread.Sleep(500); Console.WriteLine("f1 says: Hello world!"); } void f2(object o) { Thread.Sleep(1000); string s; if (o is string) s = o as string; else { // for sure using a "volatile" variable in a class as storage would be a better approach string[] h = (string[])o; s = h[0]; h[0] = "new Message"; } Console.WriteLine("f2 says: " + s); } Console.WriteLine("The parent thread id is: " + Thread.CurrentThread.ManagedThreadId); Thread t1 = new Thread(f1); // "f1 says: Hello world!" t1.IsBackground = true; // not the same as daemon! It is a background thread that is dependent from the main thread. t1.Start(); t1.Join(); string lByVal = "Agent Smith is everywhere :("; Thread t2 = new Thread(f2); // "f2 says: Agent Smith is everywhere :(" t2.Start(lByVal); string[] lByRef = { "Agent Smith is everywhere :(" }; Thread t3 = new Thread(f2); // "f2 says: Agent Smith is everywhere :(" t3.Start(lByRef); t3.Join(); Console.WriteLine("same text? " + lByRef[0]); // "same text? new Message"
class Class1 implements Runnable { @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("c1 says: Hello world!"); } } // class class Class2 implements Runnable { private Object _Parameter; public Class2(Object xParameter) { _Parameter = xParameter; } // constructor public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } String s; if (_Parameter instanceof String) s = (String)_Parameter; else { String[] h = (String[])_Parameter; s = h[0]; h[0] = "new Message"; } System.out.println("c2 says: " + s); } // } // class System.out.println("The parent thread id is: " + Thread.currentThread().getId()); Class1 lInstance1 = new Class1(); Thread t1 = new Thread(lInstance1); // "c1 says: Hello world!" t1.setDaemon(true); t1.start(); try { t1.join(); } catch (InterruptedException e) { e.printStackTrace(); } String lByVal = "Agent Smith is everywhere :("; Class2 lInstance2 = new Class2(lByVal); Thread t2 = new Thread(lInstance2); // "c2 says: Agent Smith is everywhere :(" t2.start(); String[] lByRef = {"Agent Smith is everywhere :("}; Class2 lInstance3 = new Class2(lByRef); Thread t3 = new Thread(lInstance3); // "c2 says: Agent Smith is everywhere :(" t3.start(); try { t3.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("same text? " + lByRef[0]); // "same text? new Message"
void f1() { this_thread::sleep_for(chrono::milliseconds(500)); cout << "f1 says: Hello world!" << endl; } void f2(string xMessage) { this_thread::sleep_for(chrono::milliseconds(1000)); cout << "f2 says: " << xMessage << endl; } class f3 { public: void operator()(string &xMessage) { this_thread::sleep_for(chrono::milliseconds(1500)); cout << "functor f3 says: " << xMessage << endl; xMessage = "new Message"; } }; cout << "The parent thread id is: " << this_thread::get_id() << endl; thread t1(f1); // "f1 says: Hello world!" t1.detach(); // t1 becomes a daemon process (background + no terminal) if (t1.joinable()) t1.join(); // joinable() returns false thread t2(f2, "Mr Anderson is Neo."); // "f2 says: Mr Anderson is Neo." string lByValue = "Agent Smith is everywhere :("; thread t3((f3()), lByValue); // functor f3 says: Agent Smith is everywhere :(" t2.join(); t3.join(); cout << "same text? " << lByValue << endl; // "same text? Agent Smith is everywhere :(" string lByRef = lByValue; thread t4((f3()), ref(lByRef)); // "functor f3 says: Agent Smith is everywhere :(" // so that the call by reference can assign a new value // play with this value t4.join(); cout << "same text? " << lByRef << endl; // "same text? new Message"
migration C#, Java, C++ (day 2)
Day 2. I feel some heat already 😉
managed code
public class Dog { public string Name { get; set; } public Dog() { } public Dog(string xName) { Name = xName; } } // -------------------------------------------------------------- { Dog lDog1 = new Dog(); Dog lDog2 = new Dog(); lDog1 = null; // allows the garbage collector to collect lDog1 } // leaving the scope allows lDog2 to be collected
public class Dog { public Dog() {} public Dog(String xName) { setName(xName); } private String _Name; public final String getName() { return _Name; } public final void setName(String value) { _Name = value; } } // class // -------------------------------------------------------------- { Dog lDog1 = new Dog(); Dog lDog2 = new Dog(); lDog1 = null; // allows the garbage collector to collect lDog1 } // leaving the scope allows lDog2 to be collected
// .h file #ifndef DOG_H #define DOG_H #include <string> #include <memory> using namespace std; class Dog : public enable_shared_from_this<Dog> { private: string pName; public: const string &getName() const; void setName(const string &xName); Dog(); Dog(const string &xName); }; #endif // DOG_H // .cpp file #include "Dog.h" using namespace std; Dog::Dog(){} Dog::Dog(const string &xName) { setName(xName); } const string &Dog::getName() const { return pName;} void Dog::setName(const string &value) { pName = value; } // -------------------------------------------------------------- shared_ptr<Dog> lDog1 (new Dog("Snoopy")); cout<<lDog1.use_count() << endl; // 1 shared_ptr<Dog> lDog2 = make_shared<Dog>("Lassie"); cout<<lDog2.use_count() << endl; // 1 shared_ptr<Dog> lDog3 = lDog2; cout<<lDog1.use_count() << endl; // 1 cout<<lDog2.use_count() << endl; // 2 cout<<lDog3.use_count() << endl; // 2
Dictionary
Dictionary<string, Double> lDictionary = new Dictionary<string, double>(); lDictionary.Add("-10-", 10.0); lDictionary.Add("-20-", 20.0); lDictionary.Add("-30-", 30.0); lDictionary.Add("-40-", 40.0); lDictionary.Remove("-30-"); foreach (var lPair in lDictionary) Console.WriteLine(lPair.Key + " equals " + lPair.Value); foreach (var lValue in lDictionary.Values) Console.WriteLine(lValue); Double d; if (lDictionary.TryGetValue("-10-", out d)) Console.WriteLine("found -10- which is: " + d);
java.util.HashMap<String, Double> lDictionary = new java.util.HashMap<String, Double>(); lDictionary.put("-10-", 10.0); lDictionary.put("-20-", 20.0); lDictionary.put("-30-", 30.0); lDictionary.put("-40-", 40.0); lDictionary.remove("-30-"); // C# var: There is no such as implicit typing in Java for (Entry<String, Double> lPair : lDictionary.entrySet()) System.out.println(lPair.getKey() + " equals " + lPair.getValue()); for (Double lValue : lDictionary.values()) System.out.println(lValue); double d = 0; if (lDictionary.containsKey("-10-") ? (d = lDictionary.get("-10-")) == d : false) System.out.println("found -10- which is: " + d);
unordered_map<string, double> lMap = unordered_map<string, double>(); lMap.insert(make_pair("-10-", 10.0)); lMap.insert(make_pair("-20-", 20.0)); lMap.insert(make_pair("-30-", 30.0)); lMap.insert(make_pair("-40-", 40.0)); lMap["-40-"] = 41.0; lMap.erase("-30-"); for (auto &lPair : lMap) { cout << lPair.first << " equals " << lPair.second << endl; // 10 20 41 } double d1 = lMap["-10-"]; cout << "found -10- which is: " << d1 << endl; // 10.0 double d2 = lMap["-11-"]; // returns the default value cout << "found -11- which is: " << d2 << endl; // 0.0 unordered_map<string, string> lMap2 = unordered_map<string, string>(); lMap2["hello"] = "hulla"; string s = lMap2["hola"]; if (s == "") s = "EMPTY"; cout << "lMap2[\"hola\"] == " << s << endl; // s == "EMPTY"
Queue
Queue<Dog> lDogs = new Queue<Dog>(); lDogs.Enqueue(new Dog("Boomer")); lDogs.Enqueue(new Dog("Spike")); lDogs.Enqueue(new Dog("Lassie")); Console.WriteLine(lDogs.Peek().Name); // Boomer Dog lDog = lDogs.Dequeue(); Console.WriteLine(lDogs.Peek().Name); // Spike
// Queue is not a class, just an interface java.util.Queue<Dog> lDogs = new java.util.LinkedList<Dog>(); lDogs.offer(new Dog("Boomer")); lDogs.offer(new Dog("Spike")); lDogs.offer(new Dog("Lassie")); System.out.println(lDogs.peek().getName()); // Boomer Dog lDog = lDogs.poll(); System.out.println(lDogs.peek().getName()); // Spike
#include <queue> queue<Dog*> lDogs = queue<Dog*>(); lDogs.push(new Dog("Boomer")); lDogs.push(new Dog("Spike")); lDogs.push(new Dog("Lassie")); cout << lDogs.front()->getName() << endl; // Boomer cout << lDogs.back()->getName() << endl; // Lassie lDogs.pop(); // takes Boomer from the queue cout << lDogs.front()->getName() << endl; // Spike cout << lDogs.back()->getName() << endl; // Lassie
Stack
Stack<Dog> lDogs = new Stack<Dog>(); lDogs.Push(new Dog("Boomer")); lDogs.Push(new Dog("Spike")); lDogs.Push(new Dog("Lassie")); Console.WriteLine(lDogs.Peek().Name); // Lassie Dog lDogLassie = lDogs.Pop(); Console.WriteLine(lDogs.Peek().Name); // Spike
java.util.Stack<Dog> lDogs = new java.util.Stack<Dog>(); lDogs.push(new Dog("Boomer")); lDogs.push(new Dog("Spike")); lDogs.push(new Dog("Lassie")); System.out.println(lDogs.peek().getName()); // Lassie Dog lDogLassie = lDogs.pop(); System.out.println(lDogs.peek().getName()); // Spike
stack<Dog*> lDogs = stack<Dog*>(); lDogs.push(new Dog("Boomer")); lDogs.push(new Dog("Spike")); lDogs.push(new Dog("Lassie")); cout << lDogs.top()->getName() << endl; // Lassie lDogs.pop(); // takes Lassie from the stack cout << lDogs.top()->getName() << endl; // Spike
Generics, Templates
T larger<T>(T obj1, T obj2 ) { if ((dynamic)obj1 > (dynamic)obj2) return obj1; return obj2; } // int i = larger<int>(6, 4); // i == 6 bool same<T>(T obj1, T obj2 ) where T : class { return (obj1 == obj2); } // bool b1 = same<string>("ABC", "abc"); // False bool b2 = same<string>("abc", "abc"); // True public class MyClass<T, U> where T : struct where U : class { public T MyFunc(T a, U b, T c) { return c; } } MyClass<int, string> lClass = new MyClass<int, string>(); int i = lClass.MyFunc(0, "hello", 1); // i == 1
<T extends Comparable<T>> T larger(T obj1, T obj2) { if (obj1.compareTo(obj2) > 0) return obj1; return obj2; } int i = this.<Integer>larger(6, 4); // i == 6 <T extends Comparable<T>> boolean same(T obj1, T obj2) { return (obj1 == obj2); } boolean b1 = this.<String>same("ABC", "abc"); // False boolean b2 = this.<String>same("abc", "abc"); // True class MyClass<T, U> { public final T MyFunc(T a, U b, T c) { return c; } } MyClass<Integer, String> lClass = new MyClass<Integer, String>(); int i = lClass.MyFunc(0, "hello", 1); // i == 1
template <typename T> T larger(T obj1, T obj2){ if(obj1 > obj2) return obj1; return obj2; } // int i = larger(6, 4); // i == 6 template <typename T> bool same(T obj1, T obj2){ if(obj1 == obj2) return true; return false; } // bool b1 = same("ABC", "abc"); // false bool b2 = same("abc", "abc"); // true bool b3 = same("abd", "abc"); // false template<typename T, typename U> class MyClass { U MyData; public: T MyFunc(T a, U b, T c) { return c; } void MyFunc(int a, U b) { } }; MyClass<int, string> lClass; int i = lClass.MyFunc(0, "hello", 1); // 1
simple Thread
No worries, there will be follow-ups.
private void MyThread(object x) { Console.WriteLine(x as string); } Thread lThread = new Thread(MyThread); lThread.IsBackground = true; lThread.Start("mySupaDupaaParameter");
public class MyThreadClass extends Thread { private String _Parameter; public MyThreadClass(String xParameter) { _Parameter = xParameter; } // constructor @Override public void run() { System.out.println(_Parameter); } // } // class MyThreadClass lInstance = new MyThreadClass("mySupaDupaaParameter"); Thread lThread = new Thread(lInstance); lThread.setDaemon(true); lThread.start();
#include <thread> void MyThread(string xParameter) { cout << xParameter; } thread lThread(MyThread, "mySupaDupaaParameter");
Data Binding (part 2, advanced), WPF
The new C++ posts will take a lot time. The C# posts are shorter for the next three weeks. Today I created a DataGrid and three TextBoxes. They are all linked together with pretty much no code. You can even add new items to the list. Check it out!
<Window x:Class="WpfDatabinding2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="26*" /> <ColumnDefinition Width="192*" /> <ColumnDefinition Width="285*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="10*" /> <RowDefinition Height="*" /> <RowDefinition Height="*" /> <RowDefinition Height="*" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <DataGrid AutoGenerateColumns="True" Grid.ColumnSpan="3" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" ColumnHeaderHeight="30"> </DataGrid> <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Name}" /> <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Owner}" /> <TextBox Grid.Column="1" Grid.Row="3" Text="{Binding Age}" /> </Grid> </Window>
using System.Collections.Generic; using System.Windows; using System.Windows.Documents; namespace WpfDatabinding2 { public partial class MainWindow : Window { public class Dog { public string Name { get; set; } public double Age { get; set; } public string Owner { get; set; } } // class public MainWindow() { InitializeComponent(); List<Dog> lDogs = new List<Dog>(); lDogs.Add(new Dog() { Name = "Spike", Owner = "Granny", Age = 12.6 }); lDogs.Add(new Dog() { Name = "Pluto", Owner = "Mickey Mouse", Age = 7.0 }); lDogs.Add(new Dog() { Name = "Snoopy", Owner = "Charlie Brown", Age = 5.3 }); lDogs.Add(new Dog() { Name = "Lassie", Owner = "Rudd Weatherwax", Age = 8.5 }); this.DataContext = lDogs; } // } // class } // namespace
Hard to believe, but this is it. Code does not have to be long to be powerful. The magic mostly comes from these lines:
<DataGrid AutoGenerateColumns="True" Grid.ColumnSpan="3" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" ColumnHeaderHeight="30"> </DataGrid> <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Name}" /> <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Owner}" /> <TextBox Grid.Column="1" Grid.Row="3" Text="{Binding Age}" />
migration C#, Java, C++ (day 1)
This is day 1 of this series. I am covering some tricky basics between the two languages before we get more complicated. All should be self-explanatory. There is no clear structure yet. I just picked some examples that are worth mentioning.
There is a lot of code that cannot be written in C# or C++. Sometimes the differences are quite big. I am still trying to find a solution to show such properly in a comparison without just documenting each language by itself.
Arrays
// single-dimensional array int[] a1 = new int[5]; Console.WriteLine(a1.Length); // 5 // rectangular array int[,] a2 = new int[3, 4]; Console.WriteLine(a2.Length); // 12 Console.WriteLine(a2.GetUpperBound(0)); // 2 Console.WriteLine(a2.GetUpperBound(1)); // 3 // jagged arrays int[][] a3 = new int[5][]; for (int i = 0, n = a3.Length; i < n; i++) a3[i] = new int[i + 3]; Console.WriteLine(a3.Length); // 5 Console.WriteLine(a3[3].Length); // 6 Console.WriteLine(a3.GetUpperBound(0)); // 4
// single-dimensional array int[] a1 = new int[5]; System.out.println(a1.length); // 5 // rectangular array int[][] a2 = new int[3][4]; System.out.println(a2.length); // 3 System.out.println(a2[0].length); // 4 // jagged arrays int[][] a3 = new int[5][]; for (int i = 0, n = a3.length; i < n; i++) a3[i] = new int[i + 3]; System.out.println(a3.length); // 5 System.out.println(a3[3].length); // 6
// single-dimensional array int* a0 = new int[5]; // Size cannot be determined. Use std::vector. int a1[5]; cout << sizeof(a1) << endl; // 20 bytes cout << sizeof(a1)/sizeof(a1[0]) << endl; // 5 elements // rectangular array unsigned int a2[3][4]; cout << "int[3][4]: " << sizeof(a2) << endl; // 48 cout << " int[4]: " << sizeof(*a2) << endl; // 16 cout << " int: " << sizeof(**a2) << endl; // 4 cout << " a2: " << a2 << endl; // 0x28fed0 cout << "(*a2) + 1: " << (*a2) + 1 << endl; // 0x28fed4 (4 higher) cout << " a2 + 1: " << a2 + 1 << endl; // 0x28fee0 (16 higher) // jagged arrays int** a3 = new int*[5]; for(size_t i = 0; i < 5; ++i) a3[i] = new int[i + 3]; for(size_t i = 0; i < 5; ++i) delete[] a3[i]; delete[] a3;
Pointers
// call by reference vs. call by value void CallByValue(int x) { x = 6; } void CallByRefernce1(ref int x) { x = 1; } void CallByRefernce2(out int x) { x = 2; } public int func(int x) { return x; } int h = 3; CallByValue(h); Console.WriteLine(h); // 3 CallByRefernce2(out h); Console.WriteLine(h); // 2 CallByRefernce1(ref h); Console.WriteLine(h); // 1 // this is a simple delegate (not a pointer) Func<int, int> f = func; Console.WriteLine(f(5)); // 5
public final class delegateWrapper<T> { public T invoke(T t) { return t; } } // class public final class boxingWrapper<T> { public T value; public boxingWrapper(T xValue) { value = xValue; } } // class private void CallByValue(int x) { x = 6; } private void CallByRefernce(boxingWrapper<Integer> x) { x.value = 1; } int h = 3; boxingWrapper<Integer> lWrapper = new boxingWrapper<Integer>(h); CallByValue(h); // 3 System.out.println(h); CallByRefernce(lWrapper); h = lWrapper.value; // 1 System.out.println(h); // there are no pointers or delegates in Java delegateWrapper<Integer> lDelegate = new delegateWrapper<Integer>(); h = lDelegate.invoke(5); System.out.println(h); // 5
// call by reference vs. call by value void CallByValue(int x) { x = 6; } void CallByRefernce(int &x) { x = 1; } int func(int x) { return x; } int h = 3; CallByValue(h); cout<<h<<endl; // 3 CallByRefernce(h); cout<<h<<endl; // 1 // pointer to a method int (*f)(int) = 0; f = &func; cout<< f(5) << " " << (*f)(5) << endl; // 5 5 // pointer to integers (not available in C#) int *p1; // pointer to an integer int p2[3]; // an array of 3 integers int *p3[3]; // an array of 3 pointers to integers int (*p4)[3]; // a pointer to an array of 3 integers int *(&p5)[3] = p3; // a reference to an array of 3 pointers to integers int *(*p6[3])[4]; // an array of 3 pointers to an array of 4 pointers to integers int **(*p7[2])[3]; // an array of 2 pointers to an array of 3 pointers to pointers to integers
Strings
string s = "Hello World!"; // Unicode (24 bytes) Console.WriteLine(s.Length); // 12 if (s.CompareTo("abc") > 0) Console.WriteLine("larger"); for (int i = 0, n = s.Length; i < n; i++) Console.Write(s[i] + " "); Console.WriteLine(); foreach (char lChar in s) Console.Write(lChar + " "); Console.WriteLine(); int lPosition = s.IndexOf("ll", 0); s = s.Remove(lPosition, 2) + " / " + s.Substring(lPosition, 2); Console.WriteLine(s);
String s = "Hello World!"; // Unicode (24 bytes) System.out.println(s.length()); // 12 if (s.compareTo("abc") > 0) System.out.println("larger"); for (int i = 0, n = s.length(); i < n; i++) System.out.print(s.charAt(i) + " "); System.out.println(); char[] lChars = s.toCharArray(); for (char lChar : lChars) System.out.print(lChar + " "); System.out.println(); int lPosition = s.indexOf("ll", 0); // there is no remove, so we need to simulate it String h = s.substring(0, lPosition) + s.substring(lPosition + 2); s = h + " / " + s.substring(lPosition, lPosition + 2); System.out.println(s);
// strings (null terminated ASCII codes) string s = "Hello World!"; // == {’H’, ’e’, ’l’, ’l’, ’o’, ’ ’, ’W’, ’o’, ’l’, ’d’, ’!’, ’\0’} cout<< s << ", length: " << s.length() << endl; cout<< sizeof(s) << endl; // pointer size if (s < "abc") cout << "abc is larger" << endl; // operator overloaded in string.h for (int i = 0;s[i] != '\0'; i++) cout << s[i] << " "; cout << endl; for (int i = 0, n = s.length(); i < n; i++) cout << s.at(i) << " "; // includes boundary checks and exception handling cout << endl; for (char &c : s) cout << c << " "; // includes boundary checks and exception handling cout << endl; int lPosition = s.find("ll", 0); s = s.erase(lPosition, 2) + " / " + s.substr(lPosition, 2); cout << s << endl; // wstring holds unicode characters // (wchar_t is 2 bytes on Windows, 4 bytes on Linux) const wstring lWString = L"Hello wide world :)"; wcout<<lWString<<endl; // direct output string lString(lWString.begin(), lWString.end()); cout<<lString<<endl;
#define
// preprocessor #define is used to set flags #if DEBUG Console.WriteLine("DEBUG CODE"); try { throw new Exception(); } catch (Exception ex) { Console.WriteLine(ex.StackTrace); } #else Console.WriteLine("PROD CODE"); #endif
public static boolean DEBUG = true; // There are no preprocessors in Java. // To get as close as possible to the idea of preprocessors you // can use public static variables or Dependency Injection. public void test() { if (DEBUG) { System.out.println("DEBUG CODE"); try { throw new RuntimeException(); } catch (RuntimeException ex) { for (StackTraceElement x : ex.getStackTrace()) System.out.println(x.toString()); } } else System.out.println("PROD CODE"); }
// preprocessor #define #define OMG "Oh my god!\n" cout << OMG << endl; #define add(a, b, c) a + b + c + 1 cout << add(1, 2, 3) << endl; // 7 #define DEBUG #ifdef DEBUG cout << "DEBUG CODE" << endl; #else count << "PROD CODE" << endl; #endif cout << endl; cout << "This is the line " << __LINE__ << " of file " << __FILE__ << endl; cout << "Compilation date " << __DATE__ << " " << __TIME__ << endl;
struct vs. class
struct MyStruct { public double x; } // value type class MyClass { public double x; } // reference type MyStruct lStruct1 = new MyStruct(); MyStruct lStruct2 = lStruct1; // creates a copy of lStruct1 lStruct2.x = 1.0; lStruct1.x = 99.9; Console.WriteLine(lStruct2.x); // 1.0 ! MyClass lClass1 = new MyClass(); MyClass lClass2 = lClass1; // only assigns the reference lClass2.x = 1.0; lClass1.x = 99.9; Console.WriteLine(lClass2.x); // 99.9 !
// there are no user-defined value types like struct in Java public class MyClass { public double x; } private MyClass lClass1 = new MyClass(); private MyClass lClass2 = lClass1; // assigns the reference lClass2.x = 1.0; lClass1.x = 99.9; System.out.println(lClass2.x); // 99.9
// Structs in C++ are like classes. // The main difference is that the default for structs is public, whereas the default for classes is private. // Some people say that structs are for data (no methods) only. This is not true. Both can have methods.
Cast Operations
public class Dog { } public class Husky : Dog { } public class StyleGuide { } // cast operations double pi = 3.14159265; int lInt = (int)pi; double d = lInt; Console.WriteLine(d); // 3.0 Dog lDog = new Husky(); Husky lHusky = lDog as Husky; if (lHusky != null) Console.WriteLine("A husky is a dog"); StyleGuide lStyle = new StyleGuide(); //lHusky = (Husky)lStyle; // won't compile
public class Dog { } public class Husky extends Dog { } public class StyleGuide { } double pi = 3.14159265; int lInt = (int)pi; double d = lInt; System.out.println(d); // 3.0 Dog lDog = new Husky(); Husky lHusky = (Husky)lDog; if (lHusky != null) System.out.println("A husky is a dog"); StyleGuide lStyle = new StyleGuide(); // lHusky = (Husky)lStyle; // won't compile
// cast operations double pi = 3.14159265; int lInt = static_cast<int>(pi); double d = lInt; cout<<d<<endl; // 3.0 Dog *lDog = new Husky(); Husky *lHusky = dynamic_cast<Husky*>(lDog); if (lHusky != 0) cout<<"A husky is a dog"<< endl; StyleGuide *lStyle; lHusky = dynamic_cast<Husky*>(lStyle); if (lHusky == 0) cout<<"A StyleGuide is not a dog"<< endl; const char* lConst = "Hello World"; char* lVariable = const_cast<char*>(lConst); long lAddress = 5165786; lDog = reinterpret_cast<Dog*>(lAddress); if (lDog != 0) cout<<"What a funny dog"<< endl;
Collections:List
List<string> lList = new List<string>(); lList.Add("hello"); lList.Add("world"); foreach (var lItem in lList) Console.WriteLine(lItem); lList.Clear(); lList = null;
java.util.ArrayList<String> lList = new java.util.ArrayList<String>(); lList.add("hello"); lList.add("world"); for (String lItem : lList) System.out.println(lItem); lList.clear(); lList = null;
vector<wstring> lList = vector<wstring>(); lList.push_back(L"hello"); lList.push_back(L"world"); for (wstring &lItem : lList) wcout << lItem << endl; lList.clear();
Our first class
using System; namespace DemoApp.ToCpp { public class StyleGuide : IDisposable { private bool _Disposed = false; public StyleGuide() { } private double PrivateFunc(string s) { return 5.3; } public int PublicFunc(string s) { return 0; } protected string ProtectedFunc(string s) { return s; } ~StyleGuide() { Dispose(false); } // deconstructors call Finalize() of the base class public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool xDisposing) { if (_Disposed) return; if (xDisposing) { // free objects } _Disposed = true; } // } // class } // namespace
package DemoApp.ToCpp; public class StyleGuide { public StyleGuide() {} private double PrivateFunc(String s) { return 5.3; } public final int PublicFunc(String s) { return 0; } protected final String ProtectedFunc(String s) { return s; } @Override protected void finalize() throws Throwable { // // FreeResourcesHere(); // super.finalize(); } // destructor } // class
#ifndef STYLEGUIDE_H #define STYLEGUIDE_H #include <iostream> #include <string> using namespace std; class StyleGuide { public: StyleGuide(); virtual ~StyleGuide(); int PublicFunc(string* s); protected: string ProtectedFunc(string* s); private: double PrivateFunc(string* s); }; #endif // STYLEGUIDE_H
#include "StyleGuide.h" StyleGuide::StyleGuide() {} StyleGuide::~StyleGuide() {} double StyleGuide::PrivateFunc(string *s) { return 5.3; } int StyleGuide::PublicFunc(string *s) { return 0; } string StyleGuide::ProtectedFunc(string *s) { return *s; }
Data Binding (part 1, advanced), WPF
I was studying the “Google Authentication” as I plan to write a post about it. But then I came across the WPF data binding, which I was avoiding so far, because code pieces are not easy to display in posts due to their complexity. The “Google Authentication” source code will use WPF data binding. It therefore makes sense to post about WPF data binding first. Newbies have problems with WPF. It can be quite overwhelming at the beginning. This post is not covering the basics. I expect them to be known already. I will only concentrate on some data binding with TextBoxes today.
Have a look at the XAML:
<Window x:Class="WpfDatabinding.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="194" Width="374"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Label Grid.Column="0" Grid.Row="0" Content="Value1, Init only" VerticalAlignment="Center" /> <TextBox Grid.Column=" 1" Grid.Row="0" VerticalAlignment="Center" Text="{Binding Value1, Mode=OneTime}" /> <Label Grid.Column="0" Grid.Row="1" Content="Value1, OneWay" VerticalAlignment="Center" /> <TextBox Grid.Column=" 1" Grid.Row="1" VerticalAlignment="Center" Text="{Binding Value1, Mode=OneWay}" /> <Label Grid.Column="0" Grid.Row="2" Content="Value2, OneWayToSource" VerticalAlignment="Center" /> <TextBox Grid.Column=" 1" Grid.Row="2" Text="{Binding Value2, Mode=OneWayToSource}" VerticalAlignment="Center" /> <Label Grid.Column="0" Grid.Row="3" Content="Value3, OneWay" VerticalAlignment="Center" /> <TextBox Grid.Column=" 1" Grid.Row="3" Text="{Binding Value3, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" /> <Label Grid.Column="0" Grid.Row="4" Content="Value3, TwoWay" VerticalAlignment="Center" /> <TextBox Grid.Column=" 1" Grid.Row="4" Text="{Binding Value3, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" /> <Label Grid.Column="0" Grid.Row="5" Content="Value3, TwoWay" VerticalAlignment="Center" /> <TextBox Grid.Column=" 1" Grid.Row="5" Text="{Binding Value3, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" /> </Grid> </Window>
Instead of assigning simple text literals to the TextBoxes like: Text=”Hello World!”, we assign binding definitions in curly brackets. For instance: Text=”{Binding Value2, Mode=OneWayToSource}”
In this case we connect the property “Value2” with the TextBox text. The Mode tells the binding direction:
The UpdateSourceTrigger=PropertyChanged implies that the binding source class has implemented the interface INotifyPropertyChanged, which requires the event implementation called PropertyChanged. When the program raises this event with the correct property name, which is also defined in the XAML file, then the binding will refresh the GUI element.
And here is the program. Create a BindingClass instance and assign it to the current window DataContext. There is nothing else to do. The rest is taken care of by the .Net Framework and compiler. WPF is quite abstract. A lot of code is generated out of the XAML files. You cannot see the generated code without pressing the icon “Show All Files” in the Solution Explorer. What is important to know is that we are mainly looking at partial files (here: “public partial class MainWindow : Window”). The rest is auto-generated source code.
using System.Windows; namespace WpfDatabinding { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new BindingClass(); } // } // class } // namespace
using System; using System.ComponentModel; using System.Timers; namespace WpfDatabinding { public class BindingClass : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string _Value1 = "Value1 XX:XX:XX"; private string _Value2 = "Value2 XX:XX:XX"; private string _Value3 = "Value3 XX:XX:XX"; public string Value1 { get { return _Value1; } set { _Value1 = value; RaiseEvent("Value1"); } } public string Value2 { get { return _Value2; } set { _Value2 = value; RaiseEvent("Value2"); Console.WriteLine(_Value2); } } // event has no effect public string Value3 { get { return _Value3; } set { _Value3 = value; RaiseEvent("Value3"); } } // event has effect on TwoWay public BindingClass() { Timer lTimer = new Timer(1000.0); lTimer.Elapsed += new ElapsedEventHandler(Timer_Elapsed); lTimer.Start(); } // constructor void Timer_Elapsed(object sender, ElapsedEventArgs e) { string lNow = DateTime.Now.ToString("HH:mm:ss"); Value1 = "Value1 " + lNow; } // private void RaiseEvent(string xPropertyName) { var lEvent = PropertyChanged; if (lEvent == null) return; lEvent(this, new PropertyChangedEventArgs(xPropertyName)); } // } // class } // namespace
The BindingClass is straight forward. There are no events that are triggered by the GUI. The separation of XAML and program code is a pretty cool approach.
There are three properties: Value1, Value2 and Value3.
Value1 is constantly written to by a timer event that is raised each second.
Value2 is only receiving values from the GUI, because the corresponding TextBox is using Mode=OneWayToSource. This does not print anything in the GUI, hence I added the Console.WriteLine(_Value2) statement. Check the output there. The statement RaiseEvent("Value2") has no impact, writing to a TextBox would be the wrong direction for this mode.
And RaiseEvent("Value3") only impacts TwoWay TextBoxes, but not on the OneWay TextBox.
Play with the textboxes and see what reacts on what. My hint is that the last three TextBoxes are the most interesting ones.
example output on the console window:
What happens with Value 2 ?
Remoting (part 2, advanced), WCF
WCF improves code concepts substantially. There are templates like “WCF Service Application” in Visual Studio making programming extremely easy. You get results with a few clicks.
I am concentrating on an independent code solution today. This basically is a similar solution to my remoting example in part 1. You can clearly see the differences rather than starting an entirely new project type.
We need two App.config files.
One on the client side
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <client> <endpoint name="ServerInstance" address="net.tcp://localhost/ServerInstance" binding="netTcpBinding" bindingConfiguration="tcp_Unsecured" contract="Shared.MyInterface"/> </client> <bindings> <netTcpBinding> <binding name="tcp_Unsecured"> <security mode="None" /> </binding> </netTcpBinding> </bindings> </system.serviceModel> </configuration>
and one on the server-side.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <service name="Server.ServerInstance"> <endpoint address="net.tcp://localhost/ServerInstance" binding="netTcpBinding" bindingConfiguration="tcp_Unsecured" contract="Shared.MyInterface" /> </service> </services> <bindings> <netTcpBinding> <binding name="tcp_Unsecured"> <security mode="None" /> </binding> </netTcpBinding> </bindings> </system.serviceModel> </configuration>
I guess you have already noticed the Shared.MyInterface. This is the same approach as in the classical Remoting. We share data definitions.
using System; using System.Collections.Generic; using System.ServiceModel; namespace Shared { [ServiceContract(SessionMode = SessionMode.Allowed)] public interface MyInterface { [OperationContract] List<TradeData> GetTrades(); [OperationContract] string HelloWorld(string xName); [OperationContract] DateTime Ping(); } // interface } // namespace
The shared area also needs our TradeData class, which is used inside the Interface. Do not forget the Serializable attribute. You do not necessarily get an error message. The program can simply refuse proper execution and only provide mind-boggling error messages.
using System; namespace Shared { [Serializable] public class TradeData { public DateTime tradeTime; public string ticker; public double price; public int quantity; public override string ToString() { return tradeTime.ToString("dd.MMM.yy HH:mm:ss ") + ticker + " " + quantity + " @ " + price + " EUR"; } // public TradeData(DateTime xTradeTime, string xTicker, double xPrice, int xQuantity) { tradeTime = xTradeTime; ticker = xTicker; price = xPrice; quantity = xQuantity; } // constructor } // class } // namespace
The class ServerInstance is part of the server-side. It inherits MyInterface and adds the required statements of MyInterface.
using System; using System.Collections.Generic; using System.ServiceModel; using Shared; namespace Server { [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] internal class ServerInstance : MyInterface { public List<TradeData> GetTrades() { DateTime lDummyTime = new DateTime(2014, 02, 12, 16, 30, 10); TradeData lTrade1 = new TradeData(lDummyTime, "DTE", 11.83, 100); TradeData lTrade2 = new TradeData(lDummyTime.AddSeconds(2), "DAI", 66.45, 300); TradeData lTrade3 = new TradeData(lDummyTime.AddSeconds(5), "DBK", 35.91, 100); return new List<TradeData>() { lTrade1, lTrade2, lTrade3 }; } // public string HelloWorld(string xName) { return "Hello " + xName; } // public DateTime Ping() { return DateTime.Now; } // } // class } // namespace
The server side code is relatively short. It is more or less a two liner to instantiate a ServiceHost and open it.
using System; using System.ServiceModel; using System.Threading; namespace Server { public class Program { public static void Main(string[] arguments) { Thread.Sleep(10000); // we let the client wait 10 seconds to simulate a server that is down using (ServiceHost lServiceHost = new ServiceHost(typeof(ServerInstance))) { lServiceHost.Open(); Console.WriteLine("Service is available."); Console.ReadKey(); } } // main } // class } // namespace
And the client side is not much longer. Have a look for yourself. Most of the lines are taking care of printing the data to the console window.
using System; using System.ServiceModel; using System.ServiceModel.Channels; using System.Threading; using Shared; namespace Client { public class Program { public static void Main(string[] args) { ChannelFactory<MyInterface> lFactory = new ChannelFactory<MyInterface>("ServerInstance"); MyInterface lShared = null; while (true) { try { lShared = lFactory.CreateChannel(); var o = lShared.GetTrades(); var s = lShared.HelloWorld("Mr. Ohta"); var p = lShared.Ping(); Console.WriteLine("GetTrades():"); foreach (var lTrade in o) Console.WriteLine(lTrade.ToString()); Console.WriteLine(); Console.WriteLine("HelloWorld(): " + s); Console.WriteLine(); Console.WriteLine("Ping(): " + p); break; } catch (Exception ex) { Console.WriteLine(ex.Message); Thread.Sleep(2000); } finally { IChannel lChannel = lShared as IChannel; if (lChannel.State == CommunicationState.Opened) lChannel.Close(); } } Console.ReadKey(); } // main } // class } // namespace
After starting the client and server concurrently,
you should get output results like these:
SERVER example output:
Service is available.
CLIENT example output:
Could not connect to net.tcp://localhost/ServerInstance. The connection attempt
lasted for a time span of 00:00:02.0521174. TCP error code 10061: No connection
could be made because the target machine actively refused it 127.0.0.1:808.
Could not connect to net.tcp://localhost/ServerInstance. The connection attempt
lasted for a time span of 00:00:02.0391166. TCP error code 10061: No connection
could be made because the target machine actively refused it 127.0.0.1:808.
GetTrades():
12.Feb.14 16:30:10 DTE 100 @ 11.83 EUR
12.Feb.14 16:30:12 DAI 300 @ 66.45 EUR
12.Feb.14 16:30:15 DBK 100 @ 35.91 EURHelloWorld(): Hello Mr. Ohta
Ping(): 17/02/2014 12:30:59
The error messages on the client side are as expected. They are caused by “Thread.Sleep(10000);” on the server side. I thought it would be interesting to show a server which is not running at the time when starting the client.
Put aside all the complex and confusing examples on the internet. This one here is spot on. It provides a nice and comfortable entry point into WCF. The code does not have to be complex.
I recommend YouTube for further WCF explanations.
Remoting (part 1, basics), old school
Before I come to the new WCF style Remoting, I would like to introduce the good old System.Runtime.Remoting namespace.
Remoting is a convenient way to call methods across the network. You don’t have to write messages to trigger methods on the server, wait for results and then analyse feedback messages on the client side. What could be easier than calling server methods directly?
The downside is the slowness and the missing encryption. Nevertheless, if you don’t have many server requests then Remoting is probably the right solution for you. The ease is hard to beat.
We need a library to share the syntax between the server and client. In practice you would compile the following code into a library and implement it on both sides. Don’t be lazy and only share the source code. This cannot work, because two compilers generate two different system object IDs.
In today’s example we are running the code in one Visual Studio process. We are also using the localhost. This is why we do not need an external library on both sides. We are using the same compiler object ID.
The class MarshalByRefObject enables Remoting access to objects across application domain boundaries. We need to inherit this class.
public abstract class RemotingShared : MarshalByRefObject { public const string RemotingName = "MyRemotingName"; public const string ServerIpAddress = "127.0.0.1"; public const int Port = 65432; [Serializable] public class TradeData { public DateTime tradeTime; public string ticker; public double price; public int quantity; public override string ToString() { return tradeTime.ToString("dd.MMM.yy HH:mm:ss ") + ticker + " " + quantity + " @ " + price + " EUR"; } // public TradeData(DateTime xTradeTime, string xTicker, double xPrice, int xQuantity) { tradeTime = xTradeTime; ticker = xTicker; price = xPrice; quantity = xQuantity; } // constructor } // class public abstract List<TradeData> GetTrades(); public abstract string HelloWorld(string xName); public abstract DateTime Ping(); } // class
The server overrides methods of the abstract class RemotingShared by inheriting it. We do not need to create any instance. This is done in the background by the Remoting process. The option WellKnownObjectMode.Singleton makes sure that only one instance will be created and reused. WellKnownObjectMode.SingleCall would create new instances for each incoming message.
public class RemotingSharedDerived : RemotingShared { public override List<RemotingShared.TradeData> GetTrades() { DateTime lDummyTime = new DateTime(2014, 02, 12, 16, 30, 10) ; RemotingShared.TradeData lTrade1 = new TradeData(lDummyTime, "DTE", 11.83, 100); RemotingShared.TradeData lTrade2 = new TradeData(lDummyTime.AddSeconds(2), "DAI", 66.45, 300); RemotingShared.TradeData lTrade3 = new TradeData(lDummyTime.AddSeconds(5), "DBK", 35.91, 100); return new List<TradeData>() { lTrade1, lTrade2, lTrade3 }; } // public override string HelloWorld(string xName) { return "Hello " + xName; } // public override DateTime Ping() { return DateTime.Now; } // } // class public static void StartServer() { TcpChannel lTcpChannel = new TcpChannel(RemotingShared.Port); ChannelServices.RegisterChannel(lTcpChannel, true); Type lRemotingSharedType = typeof(RemotingSharedDerived); RemotingConfiguration.ApplicationName = RemotingShared.RemotingName + "App"; RemotingConfiguration.RegisterWellKnownServiceType(lRemotingSharedType, RemotingShared.RemotingName, WellKnownObjectMode.Singleton); } //
Let’s have a look at the client now. As usual I kept the code as short as possible. Personally I do not like example programs that include too much redundant information, they can be quite confusing sometimes.
As we are on the localhost, the server has registered a ‘tcp’ channel already. We check if it exists although we already know it does. But the example program would throw an exception otherwise. Keep it in the code, it does make sense when you are remoting between two different IP addresses.
public static void StartClient() { string lPath = "tcp://" + RemotingShared.ServerIpAddress + ":" + RemotingShared.Port + "/" + RemotingShared.RemotingName; TcpChannel lTcpChannel = new TcpChannel(); if (!ChannelServices.RegisteredChannels.Any(lChannel => lChannel.ChannelName == lTcpChannel.ChannelName)) { ChannelServices.RegisterChannel(lTcpChannel, true); } RemotingShared lShared = (RemotingShared)Activator.GetObject(typeof(RemotingShared), lPath); var o = lShared.GetTrades(); var s = lShared.HelloWorld("Mr. Ohta"); var p = lShared.Ping(); Console.WriteLine("GetTrades():"); foreach (var lTrade in o) Console.WriteLine(lTrade.ToString()); Console.WriteLine(); Console.WriteLine("HelloWorld(): " + s); Console.WriteLine(); Console.WriteLine("Ping(): " + p); } //
Let’s run the code now.
public static void Test() { RemotingServer.StartServer(); RemotingClient.StartClient(); Console.WriteLine("\nPress any key to exit."); Console.ReadKey(); } //
example output:
GetTrades():
12.Feb.14 16:30:10 DTE 100 @ 11.83 EUR
12.Feb.14 16:30:12 DAI 300 @ 66.45 EUR
12.Feb.14 16:30:15 DBK 100 @ 35.91 EURHelloWorld(): Hello Mr. Ohta
Ping(): 12/02/2014 20:36:55
Press any key to exit.
Compression (part 1, basics), GZip
We have done all sorts of things with data now. Compression is next on the agenda. The consideration to apply compression deals with quantity and speed. The more data you have, or the less network/hard disk speed you have, the more attracting compression becomes.
Streaming media would still be in the stone age without complex compression. And what about backup software?
For many local network messages we see a different picture. It might take longer to compress and then send data rather than to send the corresponding raw data. For small packages it is definitely not worth it. You need larger data to make compression efficient.
Some files like MP3 or JPG should not be compressed. They are compressed already. Theses files do not get smaller. You spend a lot of time compressing data just to have a larger file afterwards.
The .Net Framework supports GZip and Zip.
Today I will show you, how GZIP could be used to compress/decompress data easily with some built-in methods of the .Net Framework. I added a StopWatch to show how much time you would spend packing data. Do the maths and see how reasonable compression is compared to your device or network speed.
You obviously would not use a MemoryStream to generate the byte data. You can replace it by eg. a NetworkStream or a FileStream.
//byte[] lData = new byte[cDataSize]; //lDecompressorStream.Read(lData, 0, cDataSize);
The above lines are commented out in the following source code example. The reason for this is that the program does not use any data header to know the raw data size in advance. Therefore the final decompressed size cannot be allocated. The example would run smoothly, because the size is known in this case, it would a questionable example though.
using System; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq;
const int cDataSize = 10000; const int cIterations = 1000; public static void Test() { Stopwatch lWatch = new Stopwatch(); lWatch.Start(); byte[] lSource = GenerateRandomData(cDataSize); for (int i = 0, n = cIterations; i < n; i++) { //byte[] lSource = GenerateRandomData(cDataSize); byte[] lCompressed = Compress(lSource); byte[] lTarget = Decompress(lCompressed); if (i < n - 5) continue; // we just print the last 5 results // compare the result with the original data Console.WriteLine("before: " + string.Join(" ", lSource.Take(20)) + " ... ,length: " + lSource.Length); Console.WriteLine("after: " + string.Join(" ", lTarget.Take(20)) + " ... ,length: " + lTarget.Length); Console.WriteLine("compressed size was: " + lCompressed.Length + " = " + (lCompressed.Length/(double)lSource.Length).ToString("0.00%")); Console.WriteLine(); } lWatch.Stop(); Console.WriteLine(); Console.WriteLine("time elapsed: " + lWatch.ElapsedMilliseconds.ToString("#,##0") + " ms"); Console.WriteLine("iterations: " + cIterations.ToString("#,##0")); Console.ReadLine(); } // // creates random data with frequent repetitions private static byte[] GenerateRandomData(int xDataSize) { byte[] lData = new byte[xDataSize]; Random lRandom = new Random(DateTime.Now.Millisecond); for (int i = 0, n = lData.Length; i < n; i++) { lData[i] = (byte)lRandom.Next(0, 10); } return lData; } // private static byte[] Compress(byte[] xData) { MemoryStream lTargetStream = new MemoryStream(); using (GZipStream lCompressorStream = new GZipStream(lTargetStream, CompressionMode.Compress)) { lCompressorStream.Write(xData, 0, xData.Length); } return lTargetStream.ToArray(); } // private static byte[] Decompress(byte[] xCompressedData) { GZipStream lDecompressorStream = new GZipStream(new MemoryStream(xCompressedData), CompressionMode.Decompress); //byte[] lData = new byte[cDataSize]; //lDecompressorStream.Read(lData, 0, cDataSize); MemoryStream lTargetStream = new MemoryStream(); lDecompressorStream.CopyTo(lTargetStream); int lLength = (int)lTargetStream.Length; byte[] lDecompressedData = new byte[lLength]; lTargetStream.Seek(0, SeekOrigin.Begin); lTargetStream.Read(lDecompressedData, 0, lLength); return lDecompressedData; } //
example output:
before: 8 5 6 1 2 3 0 8 8 6 5 5 0 4 4 8 3 2 9 0 … ,length: 10000
after: 8 5 6 1 2 3 0 8 8 6 5 5 0 4 4 8 3 2 9 0 … ,length: 10000
compressed size was: 5089 = 50.89%before: 8 5 6 1 2 3 0 8 8 6 5 5 0 4 4 8 3 2 9 0 … ,length: 10000
after: 8 5 6 1 2 3 0 8 8 6 5 5 0 4 4 8 3 2 9 0 … ,length: 10000
compressed size was: 5089 = 50.89%before: 8 5 6 1 2 3 0 8 8 6 5 5 0 4 4 8 3 2 9 0 … ,length: 10000
after: 8 5 6 1 2 3 0 8 8 6 5 5 0 4 4 8 3 2 9 0 … ,length: 10000
compressed size was: 5089 = 50.89%before: 8 5 6 1 2 3 0 8 8 6 5 5 0 4 4 8 3 2 9 0 … ,length: 10000
after: 8 5 6 1 2 3 0 8 8 6 5 5 0 4 4 8 3 2 9 0 … ,length: 10000
compressed size was: 5089 = 50.89%before: 8 5 6 1 2 3 0 8 8 6 5 5 0 4 4 8 3 2 9 0 … ,length: 10000
after: 8 5 6 1 2 3 0 8 8 6 5 5 0 4 4 8 3 2 9 0 … ,length: 10000
compressed size was: 5089 = 50.89%time elapsed: 1,274 ms
iterations: 1,000
Encryption (part 2, basics, advanced), RSA
The last post dealt with symmetric encryption. Today we are going to deal with asymmetric encryption. This involves two keys; a public and a private key.
The .NET Framework provides the RSACryptoServiceProvider and DSACryptoServiceProvider classes for asymmetric encryption.
The public key must be known to encrypt data. The private key can be used to decrypt data. You cannot use a public key to decrypt data. A good YouTube introduction about private and public keys can be found here.
The two keys are mathematically related with each other. But you cannot determine the private key by knowing the public key and vice versa.
RSA (RSACryptoServiceProvider class) is a public key algorithm with key sizes ranging from 1024 to 4096. The key sizes are obviously much larger than for the AES algorithm. They did not contribute to increased security though.
We start with key generations, which are returned in the XML format.
public static void Test4() { string lPublicKey, lPrivateKey; GetKeys(out lPublicKey, out lPrivateKey); Console.WriteLine(Environment.NewLine + " P U B L I C K E Y : " + Environment.NewLine); Console.WriteLine(lPublicKey); Console.WriteLine(Environment.NewLine + " P R I V A T E K E Y : " + Environment.NewLine); Console.WriteLine(lPrivateKey); Console.ReadLine(); } // private static void GetKeys(out string xPublicKey, out string xPrivateKey) { using (RSACryptoServiceProvider lRSA = new RSACryptoServiceProvider()) { xPublicKey = lRSA.ToXmlString(false); xPrivateKey = lRSA.ToXmlString(true); } } //
edited/formatted example output:
<!--P U B L I C K E Y :--> <RSAKeyValue> <Modulus> qfwkAyqbHnI+a2f/xh9+3zufUE6drTrT7i83t5lFwvVQp1QGxSp0wrkNl3 alkuUw48N4vfn3vbjpViB3fb0ndmpyRKx1Tffa2gYmYe2DNZw79kAR6mcJLIsedOluon93etw3cHtTef zXtj9aefTtAS6R/VNkYBKyPiwz4JbR7nM= </Modulus> <Exponent>AQAB</Exponent> </RSAKeyValue> <!--P R I V A T E K E Y :--> <RSAKeyValue> <Modulus> qfwkAyqbHnI+a2f/xh9+3zufUE6drTrT7i83t5lFwvVQp1QGxSp0wrkNl3 alkuUw48N4vfn3vbjpViB3fb0ndmpyRKx1Tffa2gYmYe2DNZw79kAR6mcJLIsedOluon93etw3cHtTef zXtj9aefTtAS6R/VNkYBKyPiwz4JbR7nM= </Modulus> <Exponent>AQAB</Exponent> <P> 0K3ebgo/zcAZ5JHM2s7O78SdiLnXthO0IGOKYHfkZeegXMb8AzKpj38DwkNigkQ+rptFmwQuMTl9Eura+BtTGQ== </P> <Q> 0IgDlR6wS5TqnJmCpqb70fqMRhrMLEwFAvJlS3SFxLd+TiZSX+up68s+mg8BhhcsgkSnaSUxkzm/JYfZhxkraw== </Q> <DP> ibEf4kXbAbzumNXncL0i6Cw4sh3GCrsHkJN9m9egGely86TMZqPIJAnwBf+GgWPcZEPJ8tYYUJyZPaE/qJQHCQ== </DP> <DQ> MsHonVNq9fq5YIS9GHNsuB+UJTxAlkeqsJzvqv4h0VAYnk0Vn+Ns6Mf/5N/iLxFU9CBh32X+OyfDLw9yE0A9IQ== </DQ> <InverseQ> CgD4wQfd6bfcJgHKmmkXmoWTkz3VT722jiQ5mwSIjbGo6sZ0zBBF8qUJNzsybpg+ilqzStcOQqwO2lqwHqnw8g== </InverseQ> <D> TiN3snTtZWuCwgDGlJ55xcg0jcf1t2Hpdf4CkMVGSj5WWvTHP+8qSTCjzNJffk0Y0jpS0JGNjor nyA2YoBZJgufWeEv2rNfTkblVaLx+1nWlFJ2hWz80XbaBeK4zpA1sf8SwnUefdxnqmjDs0Jc0vUwnhFP HfXZ6hD02uTwJxSE= </D> </RSAKeyValue>
You do not have to work with XML. You can also access binary data directly by using the methods ExportParameters or ExportCspBlob. A definition for blob can be found here.
private static void GetKeys() { using (RSACryptoServiceProvider lRSA = new RSACryptoServiceProvider()) { RSAParameters xPublicKey = lRSA.ExportParameters(false); byte[] lP = xPublicKey.P; byte[] lQ = xPublicKey.Q; byte[] lModulus = xPublicKey.Modulus; byte[] lExponent = xPublicKey.Exponent; ... byte[] xPrivateKey = lRSA.ExportCspBlob(true); } } //
We have two keys now. Let’s put that into practice.
private static void GetKeys(out string xPublicKey, out string xPrivateKey) { using (RSACryptoServiceProvider lRSA = new RSACryptoServiceProvider()) { xPublicKey = lRSA.ToXmlString(false); xPrivateKey = lRSA.ToXmlString(true); } } // public static void HowToUseAsymmetricEncryption() { string lText = "Let's encrypt and decrypt this text :)"; byte[] lData = UnicodeEncoding.Unicode.GetBytes(lText); string lPublicKey, lPrivateKey; GetKeys(out lPublicKey, out lPrivateKey); byte[] lEncrypted; using (RSACryptoServiceProvider lRSA = new RSACryptoServiceProvider()) { lRSA.FromXmlString(lPublicKey); lEncrypted = lRSA.Encrypt(lData, false); } byte[] lDecrypted; using (RSACryptoServiceProvider lRSA = new RSACryptoServiceProvider()) { lRSA.FromXmlString(lPrivateKey); lDecrypted = lRSA.Decrypt(lEncrypted, false); } string lResult = UnicodeEncoding.Unicode.GetString(lDecrypted); Console.WriteLine(lResult); Console.ReadLine(); } //
There are many ways to store keys. One is to store them on the computer, so they can be accessed from anywhere. This can be achieved by setting “RSACryptoServiceProvider.UseMachineKeyStore” to true. Or you can instantiate CspParameters and set the UseMachineKeyStore in Flags (see following example).
The UseMachineKeyStore property applies to all code in the current application domain, whereas a CspParameters object applies only to classes that explicitly reference it. By instanciating RSACryptoServiceProvider with CspParameters as the constructor parameter, the keys get stored automatically. There is no explicit Store() method.
To delete the keys simply use the RSACryptoServiceProvider instance, set PersistKeyInCsp to false and then call the method Clear().
Uncomment these two lines in the code and you will see the exception “Key not valid for use in specified state”. The keys of the new instance are not the same anymore.
private static void GetKeys(out string xPublicKey, out string xPrivateKey) { using (RSACryptoServiceProvider lRSA = new RSACryptoServiceProvider()) { xPublicKey = lRSA.ToXmlString(false); xPrivateKey = lRSA.ToXmlString(true); } } // private static CspParameters GetCspParameters() { CspParameters lCspParams = new CspParameters(); lCspParams.Flags |= CspProviderFlags.UseMachineKeyStore; // all users of this computer have access //lCspParams.Flags |= CspProviderFlags.UseUserProtectedKey; // a popup window will ask for confirmation //lCspParams.Flags |= CspProviderFlags.UseNonExportableKey; // you can use the key, but not read or export it lCspParams.KeyContainerName = "MySecretKeyContainer"; return lCspParams; } // public static void HowToUseAsymmetricEncryption2() { CspParameters lCspParams; string lText = "Let's encrypt and decrypt this text :)"; byte[] lData = UnicodeEncoding.Unicode.GetBytes(lText); string lPublicKey, lPrivateKey; GetKeys(out lPublicKey, out lPrivateKey); try { lCspParams = GetCspParameters(); // new instance byte[] lEncrypted; using (RSACryptoServiceProvider lRSA = new RSACryptoServiceProvider(lCspParams)) { lRSA.FromXmlString(lPublicKey); lRSA.FromXmlString(lPrivateKey); // assigned here to show that we assigned it to a different RSACryptoServiceProvider instance lEncrypted = lRSA.Encrypt(lData, false); byte[] x = lRSA.ExportCspBlob(true); // how to delete a KeyContainer // lRSA.PersistKeyInCsp = false; // lRSA.Clear(); } lCspParams = GetCspParameters(); // new instance to demonstrate the independence using (RSACryptoServiceProvider lRSA = new RSACryptoServiceProvider(lCspParams)) { byte[] lDecrypted = lRSA.Decrypt(lEncrypted, false); string lResult = UnicodeEncoding.Unicode.GetString(lDecrypted); Console.WriteLine(lResult); } } catch (Exception ex) { Console.WriteLine(ex.Message + Environment.NewLine); Console.WriteLine(ex.StackTrace); } Console.ReadLine(); } //
I would recommend playing with the “CspProviderFlags.UseUserProtectedKey” flag. A pop-up should show up when you uncomment the line in method GetCspParameters().
Also test the “spProviderFlags.UseNonExportableKey” flag. I added the nondescript line byte[] x = lRSA.ExportCspBlob(true) to demonstrate the effect .
The nicest exception message wins the contest 😉