Skip to content

Instantly share code, notes, and snippets.

@iarovyi
Last active February 13, 2020 07:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save iarovyi/a47653f2c5329552a689 to your computer and use it in GitHub Desktop.
Save iarovyi/a47653f2c5329552a689 to your computer and use it in GitHub Desktop.
NOTES
using System;
using System.Collections.Concurrent;
/*
async converted into a type that implements a state machine
ref and out are not allowed because not whole method is executed before method returns
You can’t use them in catch or finally blocks, non-async anonymous functions, the body of a lock statement, or unsafe code.
can return: void, //designed for compatibility with event handlers, Task, //Task<void>, Task<TResult>
CONTEXT: (http://msdn.microsoft.com/en-us/magazine/gg598924.aspx)
Asynchronous functions get back to the right thread using SynchronizationContext
Task.Run(() => { }).ConfigureAwait(continueOnCapturedContext: false); //if false we don't care about context
ConfigureAwait - mostly should be used in libraries
Different execution environments use different contexts; for example, one context
may let any thread from the thread pool execute the action it’s given. There’s more
contextual information around than just the synchronization context, but if you start
wondering how asynchronous methods manage to execute exactly where you want
them to, bear this sidebar in mind.
In order to use interfaces, various methods take
the builder (or awaiter) as a parameter using a generic type parameter that’s
constrained to implement an interface (such as IAsyncStateMachine for the state
machine). That allows the members of the interface to be called without any boxing
being required. (WHY NO BOXING)
*/
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Pipes;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
/*Sample of good API
Task<Type1> GetAsync(string id) {}
Task<Type1> GetAsync(string id, CancellationToken cancellationToken) {}
Task<Type1> GetAsync(string id, IProgress<int> progress) {}
Task<Type1> GetAsync(string id, CancellationToken cancellationToken, IProgress<int> progress) {}*/
public class Type1 {}
public class Type2 {}
private static async Task<Type1> Method1Async()
{
return await Task<Type1>.Run(() =>
{
Thread.Sleep(3000);
return new Type1();
});
}
private static async Task<Type2> Method2Async()
{
return await Task<Type2>.Run(() =>
{
Thread.Sleep(3000);
return new Type2();
});
}
/* Original Async Method
* private static async Task<String> MyMethodAsync(Int32 argument)
{
Int32 local = argument;
try
{
Type1 result1 = await Method1Async();
for (Int32 x = 0; x < 3; x++)
{
Type2 result2 = await Method2Async();
}
}
catch (Exception)
{
Console.WriteLine("Catch");
}
finally
{
Console.WriteLine("Finally");
}
return "Done";
}*/
[DebuggerStepThrough, AsyncStateMachine(typeof(StateMachine))]
private static Task<String> MyMethodAsync(Int32 argument)
{
// Create state machine instance & initialize it
StateMachine stateMachine = new StateMachine()
{
// Create builder returning Task<String> from this stub method
// State machine accesses builder to set Task completion/exception
m_builder = AsyncTaskMethodBuilder<String>.Create(),
m_state = -1, // Initialize state machine location
m_argument = argument // Copy arguments to state machine fields
};
// Start executing the state machine
stateMachine.m_builder.Start(ref stateMachine);
return stateMachine.m_builder.Task; // Return state machine's Task
}
static void Main(string[] args)
{
FooMethod();
Console.WriteLine("print key ...");
Console.ReadKey();
}
public static async void FooMethod()
{
Console.WriteLine("before");
string result = await MyMethodAsync(22);
Console.WriteLine("after");
}
// This is the state machine structure
[CompilerGenerated, StructLayout(LayoutKind.Auto)]
private struct StateMachine : IAsyncStateMachine
{
// Fields for state machine's builder (Task) & its location
public AsyncTaskMethodBuilder<String> m_builder;
public Int32 m_state;
// Argument and local variables are fields now:
public Int32 m_argument, m_local, m_x;
public Type1 m_resultType1;
public Type2 m_resultType2;
// There is 1 field per awaiter type.
// Only 1 of these fields is important at any time. That field refers
// to the most recently executed await that is completing asynchronously:
private TaskAwaiter<Type1> m_awaiterType1;
private TaskAwaiter<Type2> m_awaiterType2;
// This is the state machine method itself
void IAsyncStateMachine.MoveNext()
{
String result = null; // Task's result value
// Compiler-inserted try block ensures the state machine’s task completes
try
{
Boolean executeFinally = true; // Assume we're logically leaving the 'try' block
if (m_state == -1)
{ // If 1st time in state machine method,
m_local = m_argument; // execute start of original method
}
// Try block that we had in our original code
try
{
TaskAwaiter<Type1> awaiterType1;
TaskAwaiter<Type2> awaiterType2;
switch (m_state)
{
case -1: // Start execution of code in 'try'
// Call Method1Async and get its awaiter
awaiterType1 = Method1Async().GetAwaiter();
if (!awaiterType1.IsCompleted)
{
m_state = 0; // 'Method1Async' is completing
// asynchronously
m_awaiterType1 = awaiterType1; // Save the awaiter for when we come back
// Tell awaiter to call MoveNext when operation completes
m_builder.AwaitUnsafeOnCompleted(ref awaiterType1, ref this);
// The line above invokes awaiterType1's OnCompleted which approximately
// calls ContinueWith(t => MoveNext()) on the Task being awaited.
// When the Task completes, the ContinueWith task calls MoveNext
executeFinally = false; // We're not logically leaving the 'try'
// block
return; // Thread returns to caller
}
// 'Method1Async' completed synchronously
break;
case 0: // 'Method1Async' completed asynchronously
awaiterType1 = m_awaiterType1; // Restore most-recent awaiter
break;
case 1: // 'Method2Async' completed asynchronously
awaiterType2 = m_awaiterType2; // Restore most-recent awaiter
goto ForLoopEpilog;
}
// After the first await, we capture the result & start the 'for' loop
m_resultType1 = awaiterType1.GetResult(); // Get awaiter's result
ForLoopPrologue:
m_x = 0; // 'for' loop initialization
goto ForLoopBody; // Skip to 'for' loop body
ForLoopEpilog:
m_resultType2 = awaiterType2.GetResult();
m_x++; // Increment x after each loop iteration
// Fall into the 'for' loop’s body
ForLoopBody:
if (m_x < 3)
{ // 'for' loop test
// Call Method2Async and get its awaiter
awaiterType2 = Method2Async().GetAwaiter();
if (!awaiterType2.IsCompleted)
{
m_state = 1; // 'Method2Async' is completing asynchronously
m_awaiterType2 = awaiterType2; // Save the awaiter for when we come back
// Tell awaiter to call MoveNext when operation completes
m_builder.AwaitUnsafeOnCompleted(ref awaiterType2, ref this);
executeFinally = false; // We're not logically leaving the 'try' block
return; // Thread returns to caller
}
// 'Method2Async' completed synchronously
goto ForLoopEpilog; // Completed synchronously, loop around
}
}
catch (Exception)
{
Console.WriteLine("Catch");
}
finally
{
// Whenever a thread physically leaves a 'try', the 'finally' executes
// We only want to execute this code when the thread logically leaves the 'try'
if (executeFinally)
{
Console.WriteLine("Finally");
}
}
result = "Done"; // What we ultimately want to return from the async function
}
catch (Exception exception)
{
// Unhandled exception: complete state machine's Task with exception
m_builder.SetException(exception);
return;
}
// No exception: complete state machine's Task with result
m_builder.SetResult(result);
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
}
}
/* ANOTHER POINT OF VIEW:
public async Task<int> GetPageLength_Original()
{
var client = new WebClient();
string page = await client.DownloadStringTaskAsync("http://google.com");
return page.Length;
}
public Task<int> GetPageLength_UnderTheCovers()
{
var tcs = new TaskCompletionSource<int>();
var client = new WebClient();
var awaiter = client.DownloadStringTaskAsync("http://google.com").GetAwaiter();
Action setResult = () => {
try
{
string result = awaiter.GetResult();
tcs.SetResult(result.Length);
} catch (Exception e) {
tcs.SetException(e);
}
};
if (awaiter.IsCompleted) {
setResult();
} else {
awaiter.OnCompleted(setResult);
}
return tcs.Task;
}
*/
// ----------------- Write sync and transform to async
void Go()
{
PrintAnswerToLife();
Console.WriteLine ("Done");
}
void PrintAnswerToLife()
{
int answer = GetAnswerToLife();
Console.WriteLine (answer);
}
int GetAnswerToLife()
{
Thread.Sleep (5000);
int answer = 21 * 2;
return answer;
}
async Task Go()
{
await PrintAnswerToLife();
Console.WriteLine ("Done");
}
async Task PrintAnswerToLife()
{
int answer = await GetAnswerToLife();
Console.WriteLine (answer);
}
async Task<int> GetAnswerToLife()
{
await Task.Delay (5000);
int answer = 21 * 2;
return answer;
}
// ---------------------------------------------------------
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
/*
foreach (IPAddress a in await Dns.GetHostAddressesAsync ("albahari.com"))
Console.WriteLine (a.ToString());
*/
namespace ConsoleApplication11
{
class Program
{
static void Main(string[] args)
{
//YieldAwaitable yildWhenAwaitedToCurrentContext = Task.Yield();
//Custom awaitable sample
Task task = MainAsync();
//How to know about exception as early as possible (don't wait until we check task result)
Task<int> lengthTask = ComputeLengthAsync(null);
Console.ReadKey();
}
/* Bad version
static async Task<int> ComputeLengthAsync(string text)
{
if (text == null)
{
//We will know about this exception only after we will check task state
throw new ArgumentNullException("text");
}
await Task.Delay(500);
return text.Length;
}*/
/* Another version, one method but perfomance not for library
static Task<int> ComputeLengthAsync(string text)
{
if (text == null)
{
throw new ArgumentException("text");
}
Func<Task<int>> func = async () =>
{
await Task.Delay(500);
return text.Length;
};
return func();
}
*/
static Task<int> ComputeLengthAsync(string text)
{
if (text == null)
{
//We will know about exception wirght away
throw new ArgumentNullException("text");
}
return ComputeLengthAsyncImpl(text);
}
static async Task<int> ComputeLengthAsyncImpl(string text)
{
await Task.Delay(500); // Simulate real asynchronous work
return text.Length;
}
private async static Task MainAsync()
{
Task task1 = Task.Run(() => { Thread.Sleep(5000); throw new Exception("Message 1"); });
Task task2 = Task.Run(() => { Thread.Sleep(5000); throw new Exception("Message 2"); });
try
{
await Task.WhenAll(task1, task2);
}
catch (Exception e)
{
Console.WriteLine("Caught {0}", e.Message);
}
try
{
await Task.WhenAll(task1, task2).WithAggregatedExceptions();
}
catch (AggregateException e)
{
Console.WriteLine("Caught {0} exceptions: {1}", e.InnerExceptions.Count,
string.Join(", ", e.InnerExceptions.Select(x => x.Message)));
}
}
}
public static class TaskExtensions
{
public static AggregatedExceptionAwaitable WithAggregatedExceptions(this Task task)
{
if (task == null)
{
throw new ArgumentNullException("task");
}
return new AggregatedExceptionAwaitable(task);
}
#region Custom Awaitable
public struct AggregatedExceptionAwaitable
{
private readonly Task task;
internal AggregatedExceptionAwaitable(Task task)
{
this.task = task;
}
/*
* awaiter pattern: It has a GetAwaiter() method (instance method or extension method) and it returns an awaiter(ICriticalNotifyCompletion, IsCompleted, GetResult())
*/
public AggregatedExceptionAwaiter GetAwaiter()
{
return new AggregatedExceptionAwaiter(task);
}
}
#endregion
#region Custom Awaiter
public struct AggregatedExceptionAwaiter : ICriticalNotifyCompletion //INotifyCompletion is enough for awaiter
{
private readonly Task task;
internal AggregatedExceptionAwaiter(Task task)
{
this.task = task;
}
// Delegate most members to the task's awaiter
public bool IsCompleted { get { return task.GetAwaiter().IsCompleted; } }
public void UnsafeOnCompleted(Action continuation)
{
task.GetAwaiter().UnsafeOnCompleted(continuation);
}
public void OnCompleted(Action continuation)
{
task.GetAwaiter().OnCompleted(continuation);
}
public void GetResult()
{
// This will throw AggregateException directly on failure,
// unlike task.GetAwaiter().GetResult()
task.Wait();
}
}
#endregion
}
}
[assembly: InternalsVisibleTo("AssemblyB")]
_listener = new HttpListener(); <---- create web server in C#
Debuging tools:
• DbgCLR
• One of the lower-level debugging tools, such as WinDbg, Cordbg, or Mdbg
new StackTrace(true).ToString();
new StackTrace(exception);
var classCreatedWithoutCallingConstructor = FormatterServices.GetUninitializedObject(typeof(SomeClass));
----------------------------------------------------------------------------------
REMOVE SWITCH:
private static void MethodWithoutSwitch(object obj)
{
Print((dynamic)obj); //dynamic dispatch
}
private static void Print(int number) { Console.WriteLine("number"); }
private static void Print(string number) { Console.WriteLine("string"); }
----------------------------------------------------------------------------------
TRANSPARENCY MODEL:
[SecuritySafeCritical]
public void SomeMethod() //cannot be abused by partially trusted callers
{
UnsafeSomeMethod();
}
[SecurityCritical]
public void UnsafeSomeMethod() //partially trusted callers may fail
{
}
[SecurityCritical], if the method might be harmful if called from a less trusted
assembly
• [SecuritySafeCritical], if the method performs appropriate checks/safeguards
and can be safely called from a less trusted assembly
----------------------------------------------------------------------------------
Add to GUC:
0) give assymbly strong name
1) cmd for VS
2) gacutil /i MyAssembly.dll //gacutil /u MyAssembly - unistall
3) gacutil /l //list all regestered
----------------------------------------------------------------------------------
CULTURE:
CurrentCulture reflects the regional settings of the Windows control panel, whereas
determines default DataTime.Parse
CurrentUICulture reflects the language of the operating system.
CurrentUICulture determines the language in which the computer communicates
with the user. Australia doesn’t need a separate version of English for this purpose,
so it just uses the U.S. one.
ResourceManager, by default, uses the current thread’s CurrentUICulture property to
determine the correct satellite assembly to load.
----------------------------------------------------------------------------------
ATTRIBUTES (There are three kinds of attributes):
• Bit-mapped attributes (public, abstract, and sealed, compile to bit-mapped attributes)
• Custom attributes
• Pseudocustom attributes ([Serializable], StructLayout, In, and Out) - compiler or CLR internally optimizes
pseudocustom attributes by converting them to bit-mapped attributes
[Conditional("DEBUG")]
public class MyAttribute : Attribute{} - only if debug
----------------------------------------------------------------------------------
WRITE TO WINDOWS LOG:
const string SourceName = "MyCompany.WidgetServer";
// typically be done in application setup. typically be done in application setup.
if (!EventLog.SourceExists (SourceName)) { EventLog.CreateEventSource (SourceName, "Application"); }
EventLog.WriteEntry (SourceName, "Service started; using configuration file=...", EventLogEntryType.Information);
----------------------------------------------------------------------------------
STRING:
UTF-16 sections:
1) Basic Multingual Place (BMP) - character is 1 16-bit word
2) character is 1-2 16-bit word (unicode characters that require 2 chars to represent)
two words characters = surrogates (in range 0xD800 to 0xDFFF) new StringInfo("d");
most significant bytes:
- first significant bytes(big endian)
- last significant bytes(little endian) - default for windows
UTF-8 uses between 1 and 4 bytes to represent each cahracter (now 100 000 of 1 000 000 used)
UTF-16 uses 1-2 16-bit words to represend each character
the C# char type is itself only 16 bits wide, a UTF-16 encoding will always
use exactly 2 bytes per .NET char. This makes it easy to jump to a particular character index within a stream
EXAMPLE: but- -> [98,0, 117,0 116,0 20,32]
UTF-16 uses a 2-byte prefix to identify whether the byte pairs are written in a “littleendian” or “big-endian”
UTF-32 uses 32bits for every character (easy random access, because every character uses equal number of bytes)
string.Format("{0, -25}-{1, 25}", "leftAligned10Length", "rightAligned10Length"); == "leftAligned10Length - rightAligned10Length"
// - 25 .PadRight(25) 25 .PadLeft(25)
-----------------------------------------------------------------------------------
STRUCT:
Calling an implicitly implemented interface member on a struct does not cause boxing
interface I { void Foo(); } struct S : I { public void Foo() {} }
s.Foo(); // No boxing.
Structs:
1) cannot have parameterless constructor
because Rational[] fractions = new Rational[1000]; is a lot of calls to constructors
2) if you have consturctor you need assign all fields or call base consturtor( ... : this())
class FooClass {
public int ValueTypeField; // <-- located on heap with whole object
}
only local variables and method parameters live on the stack
objects are passed by value in C# by default
------------------------------------------------------------------------------------
ENUM
BorderSides b = (BorderSides)12345;
Console.WriteLine(b); // 12345 - value it may have may fall outside the bounds of a legal enum member
----------------------------------
C# explicitly boxes an enum instance before calling its virtual methods—such as ToString or GetType.
[Flags] public enum BorderSides { Left=1, Right=2, Top=4, Bottom=8 }
...
Console.WriteLine (BorderSides.Right.ToString()); // Right
Console.WriteLine (BorderSides.Right.GetType().Name); // BorderSides
------------------------------------------------------------------------------------
NULLABLE
(new int?()) == null new int?().ToString() == string.Empty
int? boxed to null or (object)int, there is no "boxed nullable int"
int? x = null, y = null;
bool equal = x == y;
bool notEqual = x <= y;
-----------------------------------------------------------------------------------
COMPARE:
bool yes = ((IStructuralEquatable) new object[] {"string", 123, true}).Equals(new object[] {"string", 123, true},
StructuralComparisons.StructuralEqualityComparer);
var d = new Dictionary<string, int> (StringComparer.OrdinalIgnoreCase);s
IEqualityComparer<T> - default implementation in EqualityComparer
(changes equality and hashing in hash tables)
new Dictionary<string, int>(EqualityComparer<string>.Default);
StringComparer.InvariantCultureIgnoreCase
IComparer<T>
IStructuralEquatable, IStucturalComparable
- structs implement structural comparison by default: two structs are equal if all of their fields are equal
EqualityComparer<T>.Default.Equals - This has the advantage of avoiding boxing
public interface IEquatable<T> { bool Equals (T other); }
FOR STRUCTS we can speed up to 5x by overriding Equals and again speed up by 5x by
overloading the == operator and implementing IEquatable<T> allows
unboxed equality comparisons
Here is a summary of the steps:
1. Override GetHashCode() and Equals().
2. (Optionally) overload != and ==.
3. (Optionally) implement IEquatable<T>.
-----------------------------------------------------------------------------------
GETHASHCODE:
public override int GetHashCode()
{
//return Measure2 * 31 + Measure1; // 31 = some prime number
//improve uniqueness by multiplying the larger measure by some prime number (ignoring any overflow) ???????????????????
http://stackoverflow.com/questions/1145217/why-should-hash-functions-use-a-prime-number-modulus
http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
unchecked {
int hash = 17; // 17 = some prime number
hash = hash * 31 + field1.GetHashCode(); // 31 = another prime number
hash = hash * 31 + field2.GetHashCode();
hash = hash * 31 + field3.GetHashCode();
...
return hash;
}
unchecked { // Overflow is fine, just wrap
int hash = (int) 2166136261;
// Suitable nullity checks etc, of course :)
hash = hash * 16777619 ^ field1.GetHashCode();
hash = hash * 16777619 ^ field2.GetHashCode();
hash = hash * 16777619 ^ field3.GetHashCode();
return hash;
}
unchecked {
int result = HostName.GetHashCode();
result = (result * 397) ^ Port;
result = (result * 397) ^ ServiceName.GetHashCode();
result = (result * 397) ^ DatabaseName.GetHashCode();
if (UserName != null && Password != null)
{
result = (result * 397) ^ UserName.GetHashCode();
result = (result * 397) ^ Password.GetHashCode();
}
result = (result * 397) ^ DatabaseServerType.GetHashCode();
return result;
}
unchecked {
return (UseDefaultPolicy.GetHashCode() * 397) ^ (Policy != null ? Policy.GetHashCode() : 0);
}
}
-----------------------------------------------------------------------------------
NUMBERS:
sbyte SByte 8bits (−2^7 to 2^7−1)
short Int16 16bits (−2^15 to 2^15−1)
int Int32 32bits (−2^31 to 2^31−1)
long Int64 L 64bits (−2^63 to 2^63−1)
byte Byte 8bits (0 to 2^8−1)
ushort UInt16 16bits (0 to 2^16−1)
uint UInt32 U 32bits (0 to 2^32−1)
ulong UInt64 UL 64bits (0 to 2^64−1)
float Single F 32bits ±(~10^−45 to 10^38) //scientific calculations
double Double D 64bits ±(~10^−324 to 10^308) //scientific calculations
decimal Decimal M 128bits ±(~10^−28 to 10^28) //financial calculations - where base-10-accurate
//arithmetic and hight precision required
//decimal can store any int
//non-native to processor => 10 times slower then float
//internally represented in base 10 (float and decimal in 2)
//28–29 significant figures when float 15-16
doublt million = 1E06;
float, double - float-point types (technically decimal is too float-point type)
int i1 = 100000001;
float f = i1; // Magnitude preserved, precision lost - float has less precision
int i2 = (int)f; // 100000000
-----------------------------------------------------------------------------------
C# reference pointer size is 32bits = 4bytes(32x) or 8bypes(64x) = 64bits
0 1 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0 1 1 1 0 1 0 0 0 1 1 1 1 0 0 0
|| | | | ||
|+- bit 31 | | | bit 0 -+|
| | | | |
+-- BYTE 3 -----+--- BYTE 2 ----+--- BYTE 1 ----+-- BYTE 0 -----+
| | |
+----------- WORD 1 ------------+----------- WORD 0 ------------+
| |
+--------------------------- DWORD -----------------------------+
'0x72':
0111 0010 binary
7 2 hexadecimal
-------------------------------------------------------------------------------
BITWISE OPERATORS
& The AND operator (1 if both are 1)
| The OR operator (1 if any is 1)
^ The XOR operator (1 if only one of them is 1)
fi.Attributes ^= FileAttributes.Hidden; // (Toggle hidden flag)
~ The Ones Complement or Inversion operator (revert all 1 to 0 and all 0 to 1) <-NOT
>> The Right Shift operator (shift bits to right by x)
<< The Left Shift operator. (shift bits to left by x)
//XOR swap algorithm - swap the values of two variables without using a temporary variable
int x = 31643; // you can choose another data type
int y = 134;
x ^= y;
y ^= x;
x ^= y;
Console.WriteLine(x);
Console.WriteLine(y);
byte mathPow = (byte)Math.Pow(2, 15); byte pow = 1 << 7;/*faster*/
byte divisionUsingMathPow = (byte) (8/Math.Pow(2, 2)); byte divisionUsingRightShift = 8 >> 2;/*faster*/
x << n = x * (2 ^ n) //it can be faster than using arithmetic multiplication.
x >> n = x / (2 ^ n)
x << 1 = x * 2
x << 2 = x * 4
x << 3 = x * 8
x >> 1 = x / 2
x >> 2 = x / 4
x >> 3 = x / 8
1) Bit-shift operations are fast.
2) You can store multiple flags in a single value.
1 << 10 = KB, 1 << 20 = MB, 1 << 30 = GB
-----------------------------------------------------------------------------------
GARBAGE COLLECTION ----------------------------------------------------------------
-----------------------------------------------------------------------------------
Gen0 - maximum of 16MB on 32x workstation CLR (usually form few hundreds KB to a few MB)
collection takes about 1ms (when full collection can take about 100ms)
Gen1
Gen2 - size is unbounded(Gen0 and Gen1 sizes are bounded)
LOH (Large object heap) - for objects larger then 85000 bytes, no compaction
In memory Gen2, then Gen1, then Gen0
GC.Collect(); //collect all generations
GC.Collect(0); //collect Gen0
GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); // to ensure objects with finalizers are collected
GC.AddMemoryPressure GC.RemoveMemoryPressure - inform CLR about unmanaged memory
long memoryUsed = GC.GetTotalMemory (/*perform collection first*/true);
var weak = new WeakReference (stringBuilder/*stringBuilder can be collected*/); var sb = (StringBuilder)weak.Target;
System.Threading.Timer will not cause memory leak because it doesn't have reference to object (other will cause)
Memory leak: windbg.exe, Microsoft’s CLR Profiler, SciTech’s Memory Profiler, and Red Gate’s ANTS Memory Profiler.
------------------------------------
Garbage collection notifications: http://www.codeproject.com/Articles/101136/Garbage-Collection-Notifications-in-NET
GC.RegisterForFullGCNotification GC.WaitForFullGCApproach GC.WaitForFullGCComplete "C# in nutshell page 500"
------------------------------------
GC modes and submodes:
- Workstation (It is optimized to provide for low-latency GCs in order to minimize the time when threads are suspended)
try not use a little CPU resources
- concurrent
- non-concurrent
- Server (It is optimized for resource utilization.)
one collector thread(hight priority) per CPU with it's heap section
- concurrent
- non-concurrent
non-concurrent - default
concurrent(background) - has an additional background thread that marks objects(2nd gen) concurrently while the application runs
bigger working set
-------
Latency mode (can change during runtime)
- Batch - non-concrrent GC (default for Server mode)
- Interactive - concurrent GC (default for Workstation mode)
- LowLatency - for performing short-time time-sensitive operation (will not collect 2nd generation)
- SustainedLowLatency - like LowLatency for a long time
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
FINALIZERS:
In Finalizers:
• Ensure that your finalizer executes quickly.
• Never block in your finalizer (Chapter 14).
• Don’t reference other finalizable objects.
• Don’t throw exceptions.
-----------------------------------------------------------------------------------
STREAM
Stream threadSafeStream = Stream.Synchronized(new MemoryStream());
------------------
FileStream can lock part of file:
var fs = new FileStream();
fs.Lock(position: 0, length: 100); //It's used by databases
fs.Unlock(position: 0, length: 100);
------------------
PipeStream - Stream beetwean processes
using (var s = new NamedPipeServerStream("pipedream"))
{
s.WaitForConnection();
s.WriteByte(100);
Console.WriteLine(s.ReadByte());
}
using (var s = new NamedPipeClientStream("pipedream"))
{
s.Connect();
Console.WriteLine(s.ReadByte());
s.WriteByte(200); // Send the value 200 back.
}
-----------------------------------------------------------------------------------
MEMORY-MAPPED FILES provide two key features:
• Efficient random access to file data
• The ability to share memory between different processes on the same computer
FileStreams are 10 times faster than memory-mapped files for sequential I/O.
Memory-mapped files are 10 times faster than FileStreams for random I/O.
File.WriteAllBytes("long.bin", new byte[1000000]);
//using (MemoryMappedFile mmFile = MemoryMappedFile.CreateNew ("Demo", 500)) - no disk file
using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile("long.bin"))
using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor())
{
accessor.Write(500000, (byte)77);
Console.WriteLine(accessor.ReadByte(500000)); // 77
/*unsafe - Use unsafe pointer for memory-mapped file
{
byte* pointer = null;
accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer);
int* intPointer = (int*)pointer;
Console.WriteLine(*intPointer); // 123
}*/
}
-----------------------------------------------------------------------------------
----------------------------------------------------------------
TRASH:
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < _items.Length; i++)
{
yield return _items[i];
}
}
anonymous methods
class Anonymous
{
public void Method()
{
bool test = true;
Action a = ()=> test = false;
}
}
class ILAssembled
{
public void Method()
{
nested nt = new nested();
nt.test = true;
}
private sealed class nested
{
public bool test;
public void MethodNested()
{
test = false;
}
}
}
----------------------------------------------------------------
Expression<Func<string, bool>> f = s => s.Length < 5;
ParameterExpression p = Expression.Parameter (typeof (string), "s");
MemberExpression stringLength = Expression.Property (p, "Length");
ConstantExpression five = Expression.Constant (5);
BinaryExpression comparison = Expression.LessThan(stringLength, five);
Expression<Func<string, bool>> lambda = Expression.Lambda<Func<string, bool>> (comparison, p);
Func<string, bool> runnable = lambda.Compile();
TODO: cached reflection vs compilled expression get Man.XXX at runtime
http://www.albahari.com/nutshell/predicatebuilder.aspx
----------------------------------------------------------------------------------------------
Process.GetCurrentProcess().Threads
-------------------------------------------------------------------------
context switch overhead is about 1-2 microseconds
finally not execute:
1) Environment.FailFast 2) the Uncatchable execeptions 3) Power Failure 4)StackOverflowException, ExecutingEngineException
ThreadAbortException - not guaranteed
call to the class constructor are thread safe
CLR garantees atomic read, write for:
Boolean, Char, (S)Byte, (U)Int16, (U)Int32, (U)IntPtr, Single and reference types, but not (U)Int64
(A simple read or write on a field of 32 bits or less is always atomic. Operations on 64-bit fields
are guaranteed to be atomic only in a 64-bit runtime environment, and statements that combine more
than one read/write operation are never atomic)
x++ is not thread safe (result can be a bitwise-mixture)
--------------------------------------------------------
THREAD //time-slice - tens-of-milliseconds region, switching - few-microseconds region
Thread.CurrentThread.Suspend();//depecated, blocked and resumed tharead arecompletele different things
Thread.Sleep(0) - relinquishes the thread's current time slice
Thread.Yield() - relinquishes the thread's current time slice to threads running on the same processor
(if inserting Thread.Yield() anywhere in your code breaks the program, you almost certainly have a bug)
a blocked thread yields its processor time slice, and from then on consumes no processor time
until its blocking condition is satisfied
bool blocked = (someThread.ThreadState & ThreadState.WaitSleepJoin) != 0;
ExecutionContext.SuppressFlow();
CallContext.LogicalSetData("hello", 45);
CallContext.LogicalGetData("hello");
--------------------------------------------------------
THREADPOOL
used via: 1) TPL 2) ThreadPool.QueueUserWorkItem 3) via asynchronous deleagtes (BeginXXX) 4) via BackgroundWorker 5) Timers
--------------------------------------------------------
TIMERS:
0) native timer winmm.dll
down to 1ms precision
1) general-purpose multithreaded (Multithreaded timers use the thread pool to allow a few threads to serve many timers)
10–20 ms region precision
• System.Threading.Timer
• System.Timers.Timer
2) single-threaded (will always fire on the thread that created timer- pseudo-multithreaded)
tens of milliseconds precision, but they are less accurate because the can be delayd by UI
• System.Windows.Forms.Timer (Windows Forms timer)
• System.Windows.Threading.DispatcherTimer (WPF timer)
--------------------------------------------------------
CANCELLATION:
Interrapt and Abort do not interrapt static ctors and finally
1) Thread.Interrapt throw ThreadInterraptedException on thread
2) Thread.Abort() throw ThreadAbortException - dangerous (throws right now, only after unmanaged and finnaly)
try { th.Abort(); } catch (ThreadStateException/*was suspended*/) { th.Resume();/*now it will abort*/ }
try { ... } catch (ThreadAbortException) { Thread.ResetAbort();/*will not die*/ }
GOOD PRACTICE: abort only current thread, if not need abort not current thread then
create separate domain and unload it.
3) class CancellationTokenSource {
public CancellationToken Token {get;} //token.ThrowIfCancellationRequested(); <---OperationCanceledException
public void Cancel();
}
Task task = Task.Factory.StartNew (() => { token.ThrowIfCancellationRequested(); }, token);
token.Register(() => { /*cancellation Callback*/ }); var waitHandle = token.WaitHandle;
Exceptions that do not cause app shutdown: 1) TreadAbortException 2) AppDomainUnloadException
The thread being aborted can choose to handle the ThreadAbortException, but the exception then gets automatically re-thrown at the end of the catch block
--------------------------------------------------------
THREAD-LOCAL STORAGE
1) class MyClass { [ThreadStatic] static string _everyThreadHasItsOwnCopyOfThisField; } //only for static fields
2) private ThreadLocal<string> hello = new ThreadLocal<string>(); //for non static fields
3) var _slot = Thread.GetNamedDataSlot(''); Thread.Set(Get)Data(_slot, value); //value different for threads
or var slot = new LocalDataStoreSlot();
--------------------------------------------------------
PATTERNS (both these two pattens are obsolete, use async instead):
1) Event-Bases Asynchronous Patten(EAP), samplw BackgroundWorker, WebClient
var wc = new WebClient(); wc.DownloadStringComopleted += (s, a) => {}; wc.DownloadStringAsync(new Uri("..."));
2) asynchronous method pattern(AMP): BeginXXX, EndXXX
--------------------------------------------------------
COVARIANCE (only interfaces and delgates), arrays are covariant
invariant - generic type param cannot be changed
(OUT)covariance - can be cast to base - method outcomming A obj = new B(); //IEnumerable<out T>
(IN)contra-variant - can be cast to derived - method incomming B obj = new A(); //IComparer<in T>
have more specific parameter types than its method target
--------------------------------------------------------
DEADLOCK //lock objects in a consistent order to avoid deadlocks
livelock - if user-mode construct blocks forever (waste memeory and CPU time)
deadlock - if kernel-mode construct blocks forever (waste memeory)
-----------------------------------------------------------------------
http://msdn.microsoft.com/en-us/library/ms228964.aspx
-----------------------------------------------------------------------
----------- SYNCHRONIZATION CONSTRUCTS -------------------------------
-----------------------------------------------------------------------
-----------------------------------------------------------------------
0) Asynchronous Synchronization
var cesp = new ConcurrentExclusiveSchedulerPair();
var tfExclusive = new TaskFactory(cesp.ExclusiveScheduler);
var tfConcurrent = new TaskFactory(cesp.ConcurrentScheduler);
0) Attributes:
- [MethodImpl(MethodImplOptions.Synchronized)] <-- surrounds with Monitor.Enter(this)... .Exit
private static void M() { /*lock on this, what is bad(but fast) */}
- Synchronization Context:
derive from ContextBoundObject and apply Synchronization attribute => automatic object wide lock
Don't use because: 1) deadlocks, impoverished concurrency, unintended reentrance
1) primitive
- User mode(non-blocking) (use special CPU instructions to coordinate threads(hardware coordination)) This CPU instructions block the
thread for an increadibly short perios of time. Thread that can't get resource, spins(Waste CPU time).
- VOLATILE Volatile.Read, Volatile.Write, volatile(uses Thread.MemoryBarrier(); inside)
- INTERLOCKED(0-10ns) Interlocked.Exchange ...
All of Interlocked’s methods generate a full fence. Therefore, fields that you access via Interlocked don’t
need additional fences—unless they’re accessed in other places in your program without Interlocked or a lock.
Interlocked within a loop with many iterations can be less efficient than obtaining a single lock around the
loop (although Interlocked enables greater concurrency).
- kernel moded (tho primitive: events ans semaphores. Others ara built on top)
Thread that can't get resource, then Win blocks it thread and will resume when available.
WaitHanle(abstract) SageWaitHandle fiels thats holds a Win32 kernel object handle //boolean(0 or 1) mantained by kernel
thread #1: WaitHandle.SignalAndWait (wh1, wh2); //"meet" two threads
thread #2: WaitHandle.SignalAndWait (wh2, wh1); //better: wh1.Set(); wh2.WaitOne();
----EventWaitHandle (new EventWaitHandle(false, EventResetMode.AutoReset))
//RegisterWaitForSingleObject allows do not waste therads and use instead callbacks
RegisteredWaitHandle reg = ThreadPool.RegisterWaitForSingleObject(waitHandleDerivedObj, (data, isTimeout) => { }, "Some Data", -1/*timeout*/, true/*executeOnlyOnce*/);
waitHandleDerivedObj.Set(); reg.Unregister(waitHandleDerivedObj);
--------(1000ns)AUTO_RESET_EVENT = new Semaphore(0, 1);
When multiple threads are waiting on an auto-reset event, setting the event causes only one thread to become unblocked.
var a = new AutoResetEvent(false); a.WaitOne(); /*safe area*/ a.Set();
when auto-reset event is true, it wakes up just one blocked thread, becase the kernel automatically resets event to false;
------------------------------------------------------------------------------------------------------------------
--------(1000ns)MANUAL_RESET_EVENT
When multiple threads are waiting on a manual-reset event, setting the event causes all threads to become unblocked.
------------------------------------------------------------------------------------------------------------------
----SEMAPHORE(1000ns) //Int32 mantained by kernel (unblockes when greater then 0)
When multiple threads are waiting on a semaphore, releasing the semaphore causes releaseCount threads to become unblocked
(where releaseCount is the argument passed to Semaphore’s Release method).
blocks threads while its count is 0
init count - is the number of resource accesses that will be allowed immediately
max count - is the highest count the semaphore can obtain
new Semaphore(2(init count), 3(max count), "Hello", out createdNew);
s.WaitOne(); /*here concurrently maximum 3 threads*/ s.Release(1);
Thread-agnostic(any thread can release it);
static SemaphoreSlim _sem = new SemaphoreSlim (3);
_sem.Wait(); /*only 3 threads can be here at a time*/ _sem.Release();
------------------------------------------------------------------------------------------------------------------
----Mutex(1000ns) like a C# lock, but it can work across multiple processes
//50 times slower then lock
var m = new Mutex(false, "myMutex"); m.WaitOne(); m.ReleaseMutex();
Avoid use it because it has next extra logic(with its cost):
1) Makes sure that thread calling ReleaseMutex the same thread that obtained Mutex
2) Mantains recursion calls(has recursion count)
3) system-wide scope => mostly use it to sync applications
If running under Terminal Services(rdp) it can be made visible to all terminal server
sessions by prefix its name with "Global\"
------------------------------------------------------------------------------------------------------------------
2) Complex
- Monitor(20ns)(static class) Monitor.Enter(obj), lock (SpinLock + Semaphore)
//less then 80ns and microseconds if contended
1) Mutual-exclusiv lock 2)thread ownership 3)recursion
Monitor partially implemented in native code => good performance
With static Wait, Pulse, PulseAll we can replace AutoResetEventSlim, ManualResetEventSlim, Semaphore as well as with WaitHandle static WaitAll and WaitAny methods
----------------------------------------------------------------------------
spinning very briefly can be effective when you expect a condition to be satisfied soon (perhaps within a few
microseconds) because it avoids the overhead and latency of a context switch (use SpinLock and SpinWait)
thread ties up around 1MB of memory for as long as it lives and causes an ongoing administrative overhead
(user-mode)for situations where a lock is held for a very short time(for high-concurrency scenarios): - internally uses user-mode constructs
In parallel programming, a brief episode of spinning is often preferable to blocking, as it avoids the cost
of context switching and kernel transitions. SpinLock and SpinWait are designed to help in such cases. Their
main use is in writing custom synchronization constructs ???????????????????
If you leave a spinlock contended for too long (we’re talking milliseconds at most), it will yield its time
slice, causing a context switch just like an ordinary lock. When rescheduled, it will yield again—in a
continual cycle of “spin yielding.” This consumes far fewer CPU resources than outright spinning—but more than
blocking. ???????????????????
- struct SpinLock var s = new SpinLock(true); s.Enter(ref lockTaken); s.Exit(); ???????????????????
- struct SpinWait ???????????????????
SpinWait.SpinUntil(() => { Thread.MemoryBarrier(); return _proceed; }); equals to:
var spinWait = new SpinWait(); while (!_proceed) { Thread.MemoryBarrier(); spinWait.SpinOnce(); }
SpinWait performs CPU-intensive spinning for 10 iterations before yielding(Thread.Yuild())
----------------------------------------------------------------------------
- ReaderWriterLock(100ns) - old(saved for compatability) and bad, use ReaderWriterLockSlim <-deprecated
- CountDownEvent(40ns) Internally uses ManualResetEventSlim. After it reaches o it cannot be changed.
Blocks untill its internal counter reaches 0
var c = new CountdownEvent(2); c.Signal(); c.Wait();
Can be solved easily with PLINQ and Parallel
CountDownEvent.WaitHandle can be used when method expects object based on Waithandle
- Barrier(80ns) For set of threads that are working together(wait for all participants) in parraller so that they can step throught
phases of the algorythm together. (SAMPLE:threads of GC). Uses internally ManualResetEventSlim
Alternative for 2 threads: WaitHandle.SignalAndWait (wh1, wh2);WaitHandle.SignalAndWait (wh2, wh1);
var sync = new Barrier(participantCount: 3); sync.SignalAndWait();
- non-blocking collections (System.Collections.Concurrent):
- ConcurrentDictionary(uses internally Monitor for short period of time),
- IProducerConsumerCollection<T> -Implemented as linked list(makes them less memory efficient):
- ConcurrentQueue and ConcurrentStack(lock-free, uses Interlocked),
- ConcurrentBag (internally consists of a mini-collection object per thread. If interacting with other thread's mini-collections it uses Monitor)
- BlockingCollection (uses two SemaphoreSlim objects internally)
wrapper around all of the concurrent queue, stack, and bag that allows you to add producer and consumer semantics
var bcol = new BlockingCollection<int>((IProducerConsumerCollection<int>) new ConcurrentQueue<int>());
bcol.TryAdd(1, TimeSpan.FromMilliseconds(1)); bcol.TryTake(out result, TimeSpan.FromMilliseconds(1));
BlockingCollection provides an easy means to implement producer/consumer
structures, and is a good way to limit concurrency.
- HashTable
var threadSafeWrapperForHashtable = Hashtable.Synchronized(new Hashtable());
-Hybrid
- ManualResetEventSlim(40ns) up to 50 times faster then ManualResetEvent in short wait scenarios
mres.WaitHandle can be used when method expects object based on Waithandle
- SemaphoreSlim(200ns)
- ReaderWriterLockSlim(40ns) //twice slow then lock
In case of recursion support(thread ownership) it uses inside expensive SlinLock internally.
var rwls = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion/*SupportsRecursion*/);
//if we will not specify SupportsRecursion then it will fail
rwls.EnterReadLock(); rwls.ExitReadLock();
rwls.EnterUpgradeableReadLock(); - change write or read thread //only one upgradeable lock can itself be taken out at a time - it can be useful when we need add item if its not present in collection
-----------------------------------------------------------------------
CLASSIFICATIONS:
AutoResetEvent turnstile(турникет)
ManualResetEvent simple gate
Semaphore night club
Mutual-exclusive locks: 1) SpinLock, Mutex, Monitor
- Locking constructs:
- exclusive: Monitor, Mutex, SpinLock
- nonexclusive: Semaphore(Slim), reader/writer locks
- Signaling constructs: Monitor(Wait/Pulse methods), CountdownEvent, Barrier
- Nonblocking synchronization: MemoryBarrier, Thread.VolatileRead(Write), volatile, Interlocked
-----------------------------------------------------------------------
-----------------------------------------------------------------------
-----------------------------------------------------------------------
-----------------------------------------------------------------------
-----------------------------------------------------------------------
VOLATILE: //put memory barriers before and after every instruction that reads or writes a shared field
Thread.VolatileRead() - volatile read - ACQUIRE FENCE (in reality full fence)
инструкции, стоящие после барьера, не будут перемещены в позицию до барьера
-------------------------------------------------------------------------
Thread.VolatileWrite() - volatile write - RELEASE FENCEe(in reality full fence)
инструкции, стоящие до барьера, не будут перемещены в позицию после барьера
-------------------------------------------------------------------------
Thread.MemoryBarrier() - - FULL FENCE чтения и записи расположенные
до/после барьера будут выполнены так же до/после барьера
(prevents any kind of instruction reordering or caching around that fence)
Thread.MemoryBarrier(); _complete = true; Thread.MemoryBarrier();
memory barriers(memory fences):
1) limit the effects of instruction reordering
2) no read/write caching
Implicitly generate full fence:
1) lock
2) Interlocked(all methods)
3) asynchronous callbacks that use the thread pool(Task continueation, APM callbacks(obsolete pattern), asynchronous delegates)
4) setting and waiting on signaling construct
5) Anything that relies on signaling, such as starting or waiting on a Task
[MethodImpl(MethodImplOptions.NoInlining)] //http://habrahabr.ru/post/130318/
public static int VolatileRead(ref int address)
{
int num = address; Thread.MemoryBarrier(); return num;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void VolatileWrite(ref int address, int value)
{
Thread.MemoryBarrier(); address = value;
}
--------------------------------------------------------
static void LockFreeUpdate<T> (ref T field, Func <T, T> updateFunction) where T : class
{
var spinWait = new SpinWait();
while (true) {
T snapshot1 = field;
T calc = updateFunction (snapshot1);
T snapshot2 = Interlocked.CompareExchange (ref field, calc, snapshot1);
if (snapshot1 == snapshot2) return;
spinWait.SpinOnce();
}
}
EventHandler _someDelegate; //compiler now does by default with events
public event EventHandler SomeEvent
{
add { LockFreeUpdate (ref _someDelegate, d => d + value); }
remove { LockFreeUpdate (ref _someDelegate, d => d - value); }
}
--------------------------------------------------------
PARALLEL PROGRAMMING(PFX) (PLIQ and Parallel class)
1) data parallelism -better scalse because no shared data
2) task parallelism
System.Linq.ParallelEnumerable:
1) ParallelEnumerable.Range(1, 10).
2) .AsParallel().
someLinq.AsParallel().WithMergeOptions(ParallelMergeOptions.AutoBuffered/*NoBuffered can be useful when we need result as soon as possible*/)
//without this CLR can decide do not parallelize
.WithDegreeOfParallelism(4) //4 guaranteed
.WithCancellation(token)
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
.AsOrdered(). //<-- plinq do not preserve order(for performance)
.AsUnordered()
.../*parallel*/
.AsSequential()
Prevent from being parallelized: Take, TakeWhile, Skip, and SkipWhile, SelectMany, ElementAt
Often slower(hash partitioning): Join, GroupBy, GroupJoin, Distinct, Union, Intersect, and Except
PLINQ Stategies: C# in Nutshell page 928
If the input sequence is indexable (if it’s an array or implements IList<T>), PLINQ chooses range partitioning.
Otherwise, PLINQ chooses chunk partitioning
1) Chunk partitioning(average performance) <---- dynamic element allocation(keep thread equally bisy), other stategies static
To force Partitioner.Create(collection, loadBalance: true/*chunk partitioning*/).AsParallel().
dynamically supply "chuncks" to threads => no idle threads if one finish faster
2) Range partitioning(poor or excellent performance(for long sequeuce)) - for arrays or IList<T>(indexable)
is faster for long suquences
To force: 1) ParallelEnumerable.Range 2) .ToArray() or .ToList() before
statically preallocates an eauql number of elements to each worker => if one finish faster it will be idle
3) Hash partitioning(poor preformance) - for operation that require elements comparing(GroupBy, Join...)
Hash partitioning is relatively inefficient in that it must precalculate the hashcode of every element
(so that elements with identical hashcodes can be processed on the same thread).
Aggregate:
.AsParallel().Aggregate(
() => 0, // seedFactory - returns a new local accumulator
(localTotal, n) => localTotal + n, // updateAccumulatorFunc - aggregates an element into a local accumulator
(mainTot, localTot) => mainTot + localTot, // combineAccumulatorFunc - combines a local accumulator with the main accumulator
finalResult => finalResult); // resultSelector - applies any final transformation on the end result
--------------------------------------------------------
BLOCKING COLLECTION DETAILS:
/*BlockingCollection is a wrapper around a collection that implements IProducerConsumerCollection<T> (thread safe collection)
BlockingCollection<T> is used as a wrapper for an IProducerConsumerCollection<T> instance, allowing removal attempts from
the collection to block until data is available to be removed. Similarly, a BlockingCollection<T> can be created to enforce
an upper-bound on the number of data elements allowed in the IProducerConsumerCollection<T>
lets you Take an element from the wrapped collection—blocking if no element is available
A blocking collection also lets you limit the total size of the collection, blocking the
producer if that size is exceeded. A collection limited in this manner is called a
bounded blocking collection.
public interface IProducerConsumerCollection<T> {
bool TryAdd(T item);
bool TryTake(out T item); <--remove and return an object ...
}
*/
var blockingCollection = new BlockingCollection<int>(new ConcurrentQueue<int>()); //decorator for adding consumer producer semantics and blocking
var bc = new BlockingCollection<int>();
foreach (int i in bc.GetConsumingEnumerable()) {
//Process items as they come in potentially infinite sequence
}
//bc.CompleteAdding(); - will stop adding
var dictionary = new ConcurrentDictionary<int, int>(); //not IProducerConsumerCollection<T>
var bag = new ConcurrentBag<int>(); //IProducerConsumerCollection<T> //effective add method
var queue = new ConcurrentQueue<int>(); //IProducerConsumerCollection<T>
var stack = new ConcurrentStack<int>(); //IProducerConsumerCollection<T>
bag, queue and stack classes are less memory efficient then thread-unsafe because they use linked list
//ConcurrentDictionary, ConcurrentBag, ConcurrentQueue, ConcurrentStack are not blocking, so they are user-mode constructs
//BlockingCollection adds to them blocking (adds kernel-mode constructs logic)
--------------------------------------------------------
MONITOR DETAILS: //http://stackoverflow.com/questions/9429921/dont-understand-the-need-for-monitor-pulse http://www.yoda.arachsys.com/csharp/threads/deadlocks.shtml
You use Enter/Exit to acquire exclusive access to a lock.
You use Wait/Pulse to allow co-operative notification: I want to wait for something to occur, so I enter the lock and call Wait; the notifying code will enter the lock and call Pulse.
The two schemes are related, but they're not trying to accomplish the same thing.
Consider how you'd implement a producer/consumer queue where the consumer can say "Wake me up when you've got an item for me to consume" without something like this.
-------------------------- http://www.youtube.com/watch?v=KNeEnMsE7tM http://www.codeproject.com/Articles/28785/Thread-synchronization-Wait-and-Pulse-demystified
Thread #1
lock (_locker)
{
...
Monitor.Pulse(_locker); //Wake up someone who is waiting or wakeup all of them with PulseAll
...
}
Thread.Sleep(2000);
Thread #2
lock (_locker)
{
...
Monitor.Wait(_locker); //Wait and Release lock
...
}
--------------------------
--------------------------------------------------------
LOCK:
bool lockTaken = false;
try
{
Monitor.Enter (_locker, ref lockTaken);
// Do your stuff...
}
finally { if (lockTaken) Monitor.Exit (_locker); }
Relying more on higher-level synchronization
options such as task continuations/combinators, data parallelism and
immutable types (later in this chapter) can lessen the need for locking
------------------------------------------------------------------------------
LAZY:
Lazy<T>:
Lazy<Expensive> _expensive = new Lazy<Expensive>(() => new Expensive(), isThreadSafe: true);
----------------------------------
LazyInitializer: //better performance then Lazy<T>, it uses volatile => better performance, non blocking, but it bad when too many threads
Expensive _expensive;
public Expensive Expensive
{
get { // Implement double-checked locking
LazyInitializer.EnsureInitialized (ref _expensive, () => new Expensive());
return _expensive;
}
}
------------------------------------------------------------------------------
bool isUnboundGeneric = nullableType.IsGenericType && GetType().IsGenericTypeDefinition;
bool isNullableType = nullableType.IsGenericType && nullableType.GetGenericTypeDefinition() == typeof (Nullable<>);
-----------------------------------------------------------------------------------
GET PROPERTY FASTER:
Get "Name" property of "Man" class faster than reflection: //http://msmvps.com/blogs/jon_skeet/archive/2008/08/09/making-reflection-fly-and-exploring-delegates.aspx
Func<Man, string> getForAnyFoo = (Func<Man, string>)Delegate.CreateDelegate(typeof(Func<Man, string>), null, type.GetProperty("Name").GetGetMethod());
string name = getForAnyFoo(man);
This is faster then dynamic mehod invoke because costly dynamic binding happens once
MethodInfo trimMethod = typeof(string).GetMethod("Trim", new Type[0]);
var trim = (Func<string, string>)Delegate.CreateDelegate(typeof(Func<string, string>), trimMethod);
-----------------------------------------------------------------------------------
TYPEINFO:
Type type = foo.GetType();
TypeInfo typeInfo = type.GetTypeInfo();
Some members were moved to TypeInfo for effecincy
Instead of exposing methods like GetMembers that return arrays, TypeInfo exposes properties that return IEnumerable<T>
A TypeInfo object represents the type definition itself, whereas a Type object represents a reference to the type definition.
Getting a TypeInfo object forces the assembly that contains that type to load. In comparison,
you can manipulate Type objects without necessarily requiring the runtime to load the assembly they reference.
-----------------------------------------------------------------------------------
ACCESS INTERNAL FROM OUTSIDE:
var doSomeMethod = assembly.GetType("SecureLibrary.InternalClass")
.GetMethod("InternalMethod", BindingFlags.NonPublic | BindingFlags.Instance);
var result = doSomeMethod.Invoke(instance, new object[0]);
-----------------------------------------------------------------------------------
TO INVOKE GENERIC METHOD you should:
var genericMethod = typeof (Program).GetMethod("GetDefault").MakeGenericMethod(typeof (int));
var result = genericMethod.Invoke(obj, new object[0]);
-----------------------------------------------------------------------------------
REFLECTION-ONLY CONTEXT:
Load assembly into reflection-only context (static ctor will not execute, will not affect type resolution):
Assembly a = Assembly.ReflectionOnlyLoadFrom (@"e:\demo\mylib.dll");
-----------------------------------------------------------------------------------
LOAD FEW VERSIONS of mscorlib:
Workarouns for loading few versions of mscorlib:
1) http://cciast.codeplex.com/
2) http://www.mono-project.com/Cecil
----------------------------------------------------------------------------------
SYSTEM.REFLECTION.EMIT: ????? TODO C# in nutshel page 810
Create code:
1) TypeBiulder
2) DynamicMethod (can generate only methods)
CREATE DYNAMIC TYPE:
AppDomain appDomain = AppDomain.CurrentDomain;
AssemblyName aname = new AssemblyName("MyDynamicAssembly");
AssemblyBuilder assemBuilder = appDomain.DefineDynamicAssembly(aname, AssemblyBuilderAccess.Run/*without RunAndCollect no garbage collection*/);
ModuleBuilder modBuilder = assemBuilder.DefineDynamicModule("DynModule");
TypeBuilder tb = modBuilder.DefineType("Widget", TypeAttributes.Public);
MethodBuilder methBuilder = tb.DefineMethod("SayHello", MethodAttributes.Public, null, null);
ILGenerator gen = methBuilder.GetILGenerator();
gen.EmitWriteLine("Hello world");
gen.Emit(OpCodes.Ret);
Type t = tb.CreateType();
object o = Activator.CreateInstance(t);
t.GetMethod("SayHello").Invoke(o, null); // Hello world
assemBuilder.Save("myAssembly.dll"); //Save assembly to file
--------------------------------------------------------------
DYNAMIC METHOD:
var dynMeth = new DynamicMethod("Foo", null, null, typeof(Here)/*give asscess to private of Hello*/);
ILGenerator gen = dynMeth.GetILGenerator();
gen.EmitWriteLine("Hello world");
gen.Emit(OpCodes.Ret);
dynMeth.Invoke(null, null); // Hello worl
var dynMeth = new DynamicMethod ("Foo", null, null, typeof(void));
ILGenerator gen = dynMeth.GetILGenerator();
MethodInfo writeLineInt = typeof (Console).GetMethod ("WriteLine",
new Type[] { typeof (int) });
// The Ldc* op-codes load numeric literals of various types and sizes.
gen.Emit (OpCodes.Ldc_I4, 123); // Push a 4-byte integer onto stack
gen.Emit (OpCodes.Call, writeLineInt);
gen.Emit (OpCodes.Ret);
dynMeth.Invoke (null, null); // 123
When you exit, the evaluation stack must have exactly 0 or 1
item (depending on whether your method returns a value).
DynamicMethod dynMeth = new DynamicMethod ("Foo",
typeof (int), // Return type = int
new[] { typeof (int), typeof (int) }, // Parameter types = int, int
typeof (void));
ILGenerator gen = dynMeth.GetILGenerator();
gen.Emit (OpCodes.Ldarg_0); // Push first arg onto eval stack
gen.Emit (OpCodes.Ldarg_1); // Push second arg onto eval stack
gen.Emit (OpCodes.Add); // Add them together (result on stack)
gen.Emit (OpCodes.Ret); // Return with stack having 1 value
int result = (int) dynMeth.Invoke (null, new object[] { 3, 4 } ); // 7
int x = 6;
int y = 7;
x *= y;
Console.WriteLine (x);
var dynMeth = new DynamicMethod ("Test", null, null, typeof (void));
ILGenerator gen = dynMeth.GetILGenerator();
LocalBuilder localX = gen.DeclareLocal (typeof (int)); // Declare x
LocalBuilder localY = gen.DeclareLocal (typeof (int)); // Declare y
gen.Emit (OpCodes.Ldc_I4, 6); // Push literal 6 onto eval stack
gen.Emit (OpCodes.Stloc, localX); // Store in localX
gen.Emit (OpCodes.Ldc_I4, 7); // Push literal 7 onto eval stack
gen.Emit (OpCodes.Stloc, localY); // Store in localY
gen.Emit (OpCodes.Ldloc, localX); // Push localX onto eval stack
gen.Emit (OpCodes.Ldloc, localY); // Push localY onto eval stack
gen.Emit (OpCodes.Mul); // Multiply values together
gen.Emit (OpCodes.Stloc, localX); // Store the result to localX
gen.EmitWriteLine (localX); // Write the value of localX
gen.Emit (OpCodes.Ret);
dynMeth.Invoke (null, null); // 42
----------------------------------------------------------------------------------
http://www.ultrapico.com
http://regular-expressions.info is a good online reference with lots of examples
BOOK TODO: "Mastering Regular Expressions" by Jeffrey E. F. Friedl
\ * + ? | { [ () ^ $ . # - special literals (escaped: \?)
You can make any quantifier lazy by suffixing it with the ? symbol
.* - greedy
.*? - lazy
------------------------------------------------------
ZERO_WIDTH ASSERTATIONS:
- lookbehind
positive lookbehind (?<=expr) before matcch has expr
negative lookbehind (?<!expr) before match has no expr
- lookahead
positive lookahead (?=expr) after match has expr
negative lookahead (?!expr) after match there no expr
- anchors ^ start of string $ end of string
- word boundaries
\b matches where word characters (\w) adjoin either(often used to match whole words)
Regex.Matches("Wedding in Sarajevo", @"\b\w+\b") //1) Wedding 2)in 3)Sarajevo
\b means word boundary, except in a [ ] set, in which \b means the backspace character.
-------------------------------
QUANTIFIERS: //By default, quantifiers are greedy,
* Zero or more matches
+ One or more matches
? Zero or one match //x? - x is 0 or 1 times
{n} Exactly n matches
{n,} At least n matches
{n,m} Between n and m matches
-------------------------------
CATHEGORIES:
\p matches a character in a specified category
@"\p{Lu}" - uppercase letter
@"\p{P}" - any punctuation
\p{L} Letters
\p{Lu} Uppercase letters
\p{Ll} Lowercase letters
\p{N} Numbers
\p{P} Punctuation
\p{M} Diacritic marks
\p{S} Symbols
\p{Z} Separators
\p{C} Control characters
--------------------------------------------------------
REGEX OPTIONS IN EXPRESSION ITSELF (they can be used in expressions itself):
|Enum Value | Regex code | Description
None
IgnoreCase i Ignores case (by default, regular expressions are case-sensitive)
Multiline m Changes ^ and $ so that they match the start/end of a line
instead of start/end of the string
ExplicitCapture n Captures only explicitly named or explicitly numbered
groups (see “Groups” on page 1000)
Compiled c Forces compilation of regular expression to IL
Singleline s Makes . match every character (instead of matching
every character except \n)
IgnorePatternWhitespace x Eliminates unescaped whitespace from the pattern
(We can write spaces in regex for readability)
RightToLeft r Searches from right to left; can’t be specified midstream
ECMAScript Forces ECMA compliance (by default, the implementation is not ECMA-compliant)
CultureInvariant Turns off culture-specific behavior for string comparisons
(?i) Case-insensitive match (“ignore” case)
(?m) Multiline mode; changes ^ and $ so that they match beginning and end of any line
(?n) Captures only explicitly named or numbered groups
(?c) Compiles to IL
(?s) Single-line mode; changes meaning of “.” so that it matches every character
(?x) Eliminates unescaped whitespace from the pattern
(?r) Searches from right to left; can’t be specified midstream
-------------------------------------
IGNORE CASE:
1) Match m = Regex.Match ("a", "A", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
2) in regular expression itself
var m = Regex.Match("AAAa", @"(?i)a(?-i)a"); //Aa
var m = Regex.Match("a", @"(?i)A"); //a
(?i) - ignore case
(?-i) - do not ignore case
--------------------------------------------------------
STATIC METHODS (not compiled regular expressions):
Regex.Escape (@"?")); // \? Regex.Unescape (@"\?"));
bool isMatch = Regex.IsMatch("Jenny", "Jen(ny|nifer)?");
SPLIT:
foreach (string s in Regex.Split ("oneTwoThree", @"(?=[A-Z])"))
Console.Write (s + " "); // one Two Three
Match m = Regex.Match("any colour you like", @"colou?r");
Match m1 = Regex.Match("One color? There are two colours in my head!", @"colou?rs?");
Match m2 = m1.NextMatch();
Console.WriteLine(m1); // color
Console.WriteLine(m2); // colours
--------------------------------------------------------
Compiled Regular Expressions (up to 10 times faster):
RegEx instance uses lightweight code generation (DynamicMethod in Reflection.Emit) to dynamically build and compile code tailored to that particular regular expression
Regex r = new Regex (@"sausages?"); //creates compilled regex, static methods not
--------------------------------------------------------
GROUPS
The \n syntax lets you index the group by group number n within the expression.
For example, the expression (\w)ee\1 matches deed and peep.
The brackets around the \w instruct the regular expressions engine to store the submatch
in a group (in this case, a single letter), so it can be used later. We refer to
that group later using \1, meaning the first group in the expression
Match m = Regex.Match("206-465-1918", @"(\d{3})-(\d{3}-\d{4})");
bool firstGroupIsWholeMatch = m.Value == m.Groups[0].Value;
Console.WriteLine(m.Groups[1]); // 206
Console.WriteLine(m.Groups[2]); // 465-1918
---------------------
NAMED GROUPS:
To name a captured group: (?'group-name'group-expr) or (?<group-name>group-expr)
To refer to a group: \k'group-name' or \k<group-name>
string regExWithoutNaming = @"\b(\w)\w+\1\b"//all words that start and end with the same letter.
string regEx =
@"\b" + // word boundary
@"(?'letter'\w)" + // match first letter, and name it 'letter' <--------
@"\w+" + // match middle letters
@"\k'letter'" + // match last letter, denoted by 'letter' <--------
@"\b"; // word boundary
string regFind =
@"<(?'tag'\w+?).*>" + // match first tag, and name it 'tag'
@"(?'text'.*?)" + // match text content, name it 'text'
@"</\k'tag'>"; // match last tag, denoted by 'tag'
Match m = Regex.Match("<h1>hello</h1>", regFind);
Console.WriteLine(m.Groups["tag"]); // h1
Console.WriteLine(m.Groups["text"]); // hello
--------------------------------------------------------
REPLACE:
The replacement string can reference the original match with the $0 substitution
construct. You can access any captured groups with $1, $2, $3, and so on, or ${name}
for a named group.
string text = "10 plus 20 makes 30";
Console.WriteLine(Regex.Replace(text, @"\d+", @"<$0>")); //<10> plus <20> makes <30>
string regFind =
@"<(?'tag'\w+?).*>" + // match first tag, and name it 'tag'
@"(?'text'.*?)" + // match text content, name it 'text'
@"</\k'tag'>"; // match last tag, denoted by 'tag'
string regReplace =
@"<${tag}" + // <tag
@"value=""" + // value="
@"${text}" + // text
@"""/>"; // "/>
Console.Write (Regex.Replace ("<msg>hello</msg>", regFind, regReplace)); //<msg value="hello"/>
--------------------------------------------------------
MatchEvaluator Delegate:
Regex.Replace("5 is less than 10", @"\d+", m => (int.Parse(m.Value) * 10).ToString());
//50 is less than 100
--------------------------------------------------------
COMMENTS:
(?#comment) Inline comment
#comment Comment to end of line (works only in IgnorePatternWhitespace mode)
--------------------------------------------------------
ALTERNATION: ?????????????????????????
| Logical or
(?(expr)yes|no) Matches yes if expression matches; otherwise, matches no (no is optional)
(?(name)yes|no) Matches yes if named group has a match; otherwise, matches no (no is optional)
--------------------------------------------------------
GROUPING CONSTRUCTS: ??????????????????????????
(expr) Capture matched expression expr into indexed group
(?number) Capture matched substring into a specified group number
(?'name') Capture matched substring into group name
(?'name1-name2') Undefine name2, and store interval and current group into name1;
if name2 is undefined, matching backtracks; name1 is optional
(?:expr) Noncapturing group
--------------------------------------------------------
BinaryReader and BinaryWriter might seem like odd choices for reading and writing
strings. However, they have a major advantage over StreamReader and Stream
Writer: they prefix strings with an integer indicating the length, so a BinaryReader
always knows exactly how many bytes to read
----------------------------------------------------------------------------------
SERIALIZE ENGINES:
Serialization (engines + formatters):
• (Engine 1) The data contract serializer - DataContractAttribute, it understands Serializable
• (Engine 2)The binary serializer (except in the Metro profile) - ISerializable, SerialazableAttribute
binary engine can handle large graphs without special assistance.
performance degrades in proportion to the number of references in your object graph
• (Engine 3)The (attribute-based) XML serializer (XmlSerializer)
• The IXmlSerializable interface (good control over the XML)
implement IXmlSerializable and then use XmlReader and XmlWriter to manually read and write the XML
remoting used implicitly binary searialiation engine (OLD)
ASMX Web Services used implicitly XmlSerializer (OLD)
WCF used implicitly data contract serialization engine (NEW, based on previous)
---------------------------------------
Serializing Hooks:
[DataContract(Name = "Worker")] public class Man {
[OnSerializing] //[OnSerialized]
void PrepareForSerialization(StreamingContext sc/*used by binary engine, not contracts*/) {
//handy place logic for creating generic collections with SoapFormatter, because SoapFormatter doesn't understand generics
}
[OnDeserialized] //[OnDeserializing]
void CompleteDeserialization(StreamingContext sc) {
//handy place for constructor logic because on deserialization ctor is not called
}
}
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
DATACONTRACT SERIALIZATION ENGINE ------- (This engine understand binary serialization attributes and interfaces)
-----------------------------------------------------------------------------------
var manSerializer = new DataContractSerializer(typeof(Man));
manSerializer.WriteObject(stream, man);
var deserialized = (Man)manSerializer.ReadObject(stream);
[DataMember] supports both fields and properties—public and private. The field or
property’s data type can be any of the following:
• Any primitive type
• DateTime, TimeSpan, Guid, Uri, or an Enum value
• Nullable versions of the above
• byte[] (serializes in XML to base 64)
• Any “known” type decorated with DataContract
• Any IEnumerable type (see the section “Serializing Collections” on page 724
later in this chapter)
• Any type with the [Serializable] attribute or implementing ISerializable (see
the section “Extending Data Contracts” on page 707 later in this chapter)
• Any type implementing IXmlSerializable
-------------------------------------
DataContractSerizlier (uses XmlFormatter by default):
DataContractSerializer - Loosely couples .NET types to data contract types
var manSerializer = new DataContractSerializer(typeof(Man));
need to register “known types”
<Person xmlns="...">
...
</Person>
data contract deserializers bypass field initializers and constructors
limitation of the data contract serializer is that it gives you little control over the
structure of the XML.
NetDataContractSerializer - Tightly couples .NET types to data contract types
var netSerializer = new NetDataContractSerializer();
<Person z:Type="SerialTest.Person" z:Assembly="SerialTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
...
</Person>
---------------------------------------
Preserve reference:
The NetDataContractSerializer always preserves referential equality. The DataCon
tractSerializer does not, unless you specifically ask it to.
This means that if the same object is referenced in two different places, a DataCon
tractSerializer ordinarily writes it twice.
var ds = new DataContractSerializer(typeof(Man), null, 1000, false, preserveObjectReferences: true, dataContractSurrogate: null);
<HomeAddress z:Id="2">
<Postcode z:Id="3">6020</Postcode>
<Street z:Id="4">Odo St</Street>
</HomeAddress>
<Name z:Id="5">Stacey</Name>
<WorkAddress z:Ref="2" i:nil="true" />
---------------------------------------
Version Tolerance (data contract serializer):
Don’t complain if any [DataMember] is missing in the serialization stream.
To require add IsRequired: [DataMember (IsRequired=true)] public int ID;
public class Man : IExtensibleDataObject { //round-tripping different versions
/*IExtensibleDataObject is about serialization, and it can be used outside of WCF's service stack. Its main purpose is round-tripping different versions of a data contract without losing information*/
ExtensionDataObject /*only private members*/ IExtensibleDataObject.ExtensionData { get; set; }
}
---------------------------------------
Order: //serializer skip over any members considered out of sequence.
Members are written in the following order when serializing:
1. Base class to subclass
2. Low Order to high Order (for data members whose Order is set)
3. Alphabetical order (using ordinal string comparison)
[DataMember (Order=0)] public string Name;
member between a base class and a subclass => need [DataMember (Order
---------------------------------------
Null or empty values:
There are two ways to deal with a data member whose value is null or empty:
1. Explicitly write the null or empty value (the default).
2. Omit the data member from the serialization output.
[DataMember (EmitDefaultValue=false)] public string Name;
---------------------------------------
Collections:
[CollectionDataContract (ItemName="Residence")] public class AddressList : Collection<Address> { }
[CollectionDataContract (ItemName="Entry", KeyName="Kind", ValueName="Number")]
public class PhoneNumberList : Dictionary <string, string> { }
---------------------------------------
Interoperating with [Serializable], data contract serializer understand it
Unfortunately, the data contract serializer is inefficient in how it formats data added via ISerializable.
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
BINARY SERIALIZATION ENGINE -------------------------------------------------------
-----------------------------------------------------------------------------------
var serializer = new BinaryFormatter(); //new SoapFormatter();
serializer.Serialize(stream, man);
var resd = serializer.Deserialize(stream); //deserializer bypasses all constructors when re-creating objects. FormatterServices.GetUninitializedObject
1) no field - exception
2) extra field - BinaryFormatter is ok, but SoapFormatter thows an exception
=> use the binary formatter if two-way versioning robustness is required or ISerizlizable
For good versioning:
- avoid renaming and deleting fields
- avoid retrospectively adding the NonSerialized attribute.
- Never change a field’s type.
Formatters:
1) BinaryFormatter
2) SoapFormatter
is less functional than the BinaryFormatter. The SoapFormatter doesn’t support generic types or the filtering
of extraneous data necessary for version tolerant serialization
The following things flag a type as being serializable for the binary engine:
• The [Serializable] attribute (easier)
The [Serializable] attribute instructs the serializer to include all fields in the type.
This includes both private and public fields (but not properties). Every field must
itself be serializable; otherwise, an exception is thrown.
The Serializable attribute is not inherited
With automatic properties, the binary serialization engine serializes
the underlying compiler-generated field. The name of this
field, unfortunately, can change when its type is recompiled,
breaking compatibility with existing serialized data. The workaround
is either to avoid automatic properties in [Serializa
ble] types or to implement ISerializable.
[Serializable]
public class Adress {
public string Destination;
[NonSerialized] public int Age;
[OptionalField (VersionAdded/*version only for documetation*/ = 2)] public DateTime DateOfBirth;
}
• Implementing ISerializable (is more flexible.)
1) Dynamically control what gets serialized.
2) Make your serializable type friendly to being subclassed by other parties.
[Serializable] //1) attribute
public class Man : ISerializable {
public string Name;
public Man() { }
protected Man(SerializationInfo info, StreamingContext context) { //2) constructor
Name = (string)info.GetValue("Name"/*any key*/, typeof(string));
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { //3) interface
info.AddValue("Name", Name);
info.AddValue ("_version", 2); // custom version system
}
}
if serializable class is not sealed then implement ISerializable because if we use
just attribute and then later we will use interface - it will break derived classes
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
XML SERIALIZATION ENGINE (XmlSerializer) ------------------------------------------
-----------------------------------------------------------------------------------
• attributes (defined in System.Xml.Serialization).
[XmlInclude (typeof (Student))]//derived types
[XmlRoot ("Candidate", Namespace = "http://mynamespace/test/")] //change name ande
// add namespace to element and its children
public class Person {
[XmlIgnore] public DateTime DateOfBirth;
[XmlAttribute ("RoughAge")] public int Age; // by default xml element
[XmlElement (Order = 2)]
[XmlElement ("FirstName")] public string Name;
[XmlArray ("PreviousAddresses")]
[XmlArrayItem ("Location")]
public List<Address> Addresses = new List<Address>();
}
• Implement IXmlSerializable (completely your logic using XmlReader and XmlWriter)
public class Man : IXmlSerializable {
public string Name;
XmlSchema IXmlSerializable.GetSchema() { return null; }
void IXmlSerializable.ReadXml(XmlReader reader) { //read start, content, end
reader.ReadStartElement();
Name = reader.ReadElementContentAsString("Name", "");
reader.ReadEndElement();
}
void IXmlSerializable.WriteXml(XmlWriter writer) {//write just content
writer.WriteElementString("Name", Name);
}
}
- can serialie types without any attributes
- By default, it serializes all public fields and properties on a type
- does not recognize the [OnDeserializing]
- relies on a parameterless constructor for deserialization, throwing an exception if no one
=> field initializers execute prior to deserialization
- deserializer can work even if elements in any order
- two rererences the same object, that object is serialized twice (use other engine - solution)
var serializer = new XmlSerializer(typeof(Man));
serializer.Serialize(stream, man);
var deserialized = serializer.Deserialize(stream);
recognizes the following types and treats them specially:
• The primitive types, DateTime, TimeSpan, Guid, and nullable versions
• byte[] (which is converted to base 64)
• An XmlAttribute or XmlElement (whose contents are injected into the stream)
• Any type implementing IXmlSerializable
• Any collection type
-----------------------------------------------------------------------------------
Task.Factory.ContinueWhenAny(new[] { task0, task1, task2, task3 }, (t) => { });
Task.WhenAny
-----------------------------------------------------------------
TASK:
TaskScheduler.UnobservedTaskException += (sender, e) => { };
task1.ContinueWith((t) => { /*continue on the same thread - can improve performance*/ }, TaskContinuationOptions.ExecuteSynchronously);
public static void IgnoreExceptions (this Task task)
{
task.ContinueWith (t => { var ignore = t.Exception; /*add some logging*/ },
TaskContinuationOptions.OnlyOnFaulted);
}
Task.Factory.StartNew (() => { throw null; }).IgnoreExceptions();
-----------------------------------------------------------------
TASK SCHEDULER:
1) default
var factory = new TaskFactory (TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent, TaskContinuationOptions.None);
2) synchronization context scheduler (WPF, Windows Forms)
// Suppose we are on a UI thread in a Windows Forms / WPF application:
_uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
3) custom
4) alternative: use TaskCompletionSource
-----------------------------------------------------------------
Tasks: (anything that might take longer than 50ms need to be written asynchronously)
var factory = new TaskFactory (TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent,TaskContinuationOptions.None);
TaskScheduler.UnobservedTaskException event //in .NET 4.0 unobserved exception terminates the program, in 4.5 they not.
-----------------------------------------------------------------
WHEN ANY
Task<int> firstCompletedTask = await Task.WhenAny(task1, task2, task3);
int firstCompletedTaskResult = await await Task.WhenAny(Delay1(), Delay2(), Delay3());
If a non-winning task subsequently faults, the exception will go unobserved unless you subsequently await the task
(or query its Exception property).
ADD TIMEOUT to tasks without timeouts:
Task<string> task = SomeAsyncFunc();
Task winner = await (Task.WhenAny (someOperation, Task.Delay(5000)));
if (winner != task) throw new TimeoutException();
string result = await task; // Unwrap result/re-throw
-----------------------------------------------------------------
WHEN ALL
Task task1 = Task.Run(() => { throw null; });
Task task2 = Task.Run(() => { throw null; });
Task all = Task.WhenAll(task1, task2);
try { await all; }
catch (Exception ex /*HERE will be NullReferenceException from task1 */)
{
Console.WriteLine(all.Exception.InnerExceptions.Count); // 2
}
-----------------------------------------------------------------
Task.FromResult("abc"); - creates already signaled task.
Task.Run(() => { }).ContinueWith((t) => { /*execute on the same thread*/ }, TaskContinuationOptions.ExecuteSynchronously);
Task.Factory.StartNew(() => { /*request non-pooled thread: Thread.CurrentThread.IsThreadPoolThread == false*/ }, TaskCreationOptions.LongRunning);
//All task that do not satisfy TaskContinuationOptions will be considered cancelled and all further tasks will be called unless
//they have NotOnCanceled or OnlyOnRanToCompletion
Task.Factory.StartNew(() => { })
.ContinueWith((t) => {/*cancelled task because previous was not faulted*/ }, TaskContinuationOptions.OnlyOnFaulted)
.ContinueWith((t) => { /*will be called*/});
Task<int> readChunk = Task<int>.Factory.FromAsync (stream.BeginRead, stream.EndRead, data, bytesRead, data.Length - bytesRead, null);
-----------------------------------------
Task without ThreadPool:
var source = new TaskCompletionSource<int>();
new Thread(() => { try { Thread.Sleep(5000); source.SetResult(123); } catch(e) { source.SetException (e); } }).Start();
Task<int> task = source.Task; // Our "slave" task.
Console.WriteLine(task.Result); // 123
Handle AggregateException:
aggregateException.Flatten().Handle(e => true); //If any e => false then Handle method will throw new AggregateException
---------------------------------------------------------------------------
WAITHANDLE TO TASK:
public static class WaitHandleExtensions {
/*
* _autoResetEvent.ToTask().ContinueWith((t) => { Console.WriteLine("It's completed"); });
*/
public static Task<bool> ToTask(this WaitHandle waitHandle, int timeout = -1) {
var tcs = new TaskCompletionSource<bool>();
RegisteredWaitHandle token = null;
var tokenReady = new ManualResetEventSlim();
token = ThreadPool.RegisterWaitForSingleObject(waitHandle, (state, timedOut) =>
{
tokenReady.Wait(); //because in race condition it can execute before
tokenReady.Dispose(); //token variable is assigned
token.Unregister(waitHandle);
tcs.SetResult(!timedOut);
}, null, timeout, true);
tokenReady.Set();
return tcs.Task;
}
}
------------------------------------------------------------------------
AWAIT:
someTask.GetAwaiter().GetResult() - throws not AggregatedException, but original exception
Task.Run(() =>{ }).GetAwaiter().OnCompleted(() => {/*when task finishes or faults*/ });
public interface IAwaiter_IMAGINE_THERE_IS_NO_INTERFACE : INotifyCompletion { // or ICriticalNotifyCompletion
// INotifyCompletion has one method: void OnCompleted(Action continuation);
// ICriticalNotifyCompletion implements INotifyCompletion,
// also has this method: void UnsafeOnCompleted(Action continuation);
bool IsCompleted { get; }
void GetResult(); //exception thrown here is not wrapped with aggregation exception
}
await can't be used: inside a catch or finally block, lock expression, unsafe context or an executable’s entry point (main method).
Awaiting an asynchronous function that returns synchronously still incurs a small overhead—maybe 50-100 nanoseconds
async functions design principles:
(async functions should be made of sync ones just by adding async and await)
1. Write your methods synchronously.
2. Replace synchronous method calls with asynchronous method calls, and await them.
3. Except for “top-level” methods (typically event handlers for UI controls), upgrade your asynchronous methods’
return types to Task or Task<TResult> so that they’re awaitable.
SYNCHRONIZATION CONTEXT:
The exception is posted to the synchronization context (if present) and never to the caller
If a synchronization context is present, void-returning asynchronous functions also call its OperationStarted method upon
entering the function, and its OperationCom pleted method when the function finishes
public class SynchronizationContext {
public virtual void OperationStarted() { ... }
public virtual void OperationCompleted() { ... }
}
var context = SynchronizationContext.Current; context.Post((stateObj) => { }, null);
PROGRESS:
public interface IProgress<in T> { void Report (T value); }
var progress = new Progress<int> (i => Console.WriteLine (i + " %"));
Upon instantiating Progress<int>, the class captures the synchronization context, if present. When Foo then calls Report, the delegate is invoked through that context.
The Task-based Asynchronous Pattern (TAP):
• Returns a “hot” (running) Task or Task<TResult>
• Has an “Async” suffix (except for special cases such as task combinators)
• Is overloaded to accept a cancellation token and/or IProgress<T> if it supports cancellation and/or progress reporting
• Returns quickly to the caller (has only a small initial synchronous phase)
• Does not tie up a thread if I/O-bound As we’ve seen, TAP methods are easy to write with C#’s asynchronous functions.
async Task<int> GetTotalSize(string[] uris)
{
IEnumerable<Task<int>> downloadTasks = uris.Select(async uri =>
(await new WebClient().DownloadDataTaskAsync(uri)).Length
);
int[] contentLengths = await Task.WhenAll(downloadTasks);
return contentLengths.Sum();
}
& The address-of operator returns a pointer to the address of a variable
* The dereference operator returns the variable at the address of a pointer
-> The pointer-to-member operator is a syntactic shortcut, in which x->y is equivalent to (*x).y
var mySctuct = new MySctruct();
MySctruct* mySctuctAddresPointer = &mySctuct;
mySctuctAddresPointer->x = 5;
--------------------------------------------------------
unsafe {
//any value type, an array of value types, or a string
fixed (int* d = &myClass.number) {//& -address-of operator
*d = 77; //* -dereference operator (value)
}
}
------------------------------------------------------------------------------------------------
void*
A void pointer (void*) makes no assumptions about the type of the underlying data
and is useful for functions that deal with raw memory. An implicit conversion exists
from any pointer type to void*. A void* cannot be dereferenced
unsafe static void Main()
{
short[ ] a = {1,1,2,3,5,8,13,21,34,55};
fixed (short* p = a) {
CleanMemoryBlock(p, a.Length * sizeof (short)); //sizeof returns size of value-type in bytes
}
foreach (short x in a) {
System.Console.WriteLine (x); // Prints all zeros
}
}
unsafe static void CleanMemoryBlock(void* memory, int byteCount)
{
byte* b = (byte*) memory;
for (int i = 0; i < byteCount; i++) {
*b++ = 0;
}
}
------------------------------------------------------------------------------------------------
STACKALLOC
int* stackArray = stackalloc int[10];
for (int i = 0; i < 10; i++) {
Console.WriteLine(stackArray[i]);
}
byte* bytes = stackalloc byte[this.m_StringHeapByteLength];
------------------------------------------------------------------------------------------------
FIXED - for pinning inlined value types within reference types
(any value type, an array of value types, or a string)
Within a fixed statement, you can get a pointer to any value type, an array of value
types, or a string. In the case of arrays and strings, the pointer will actually point to
the first element, which is a value type
int length = bitmap.Length;
bitmap = new int[5, 5];
fixed (int* b = bitmap) {
int* p = b;
for (int i = 0; i < length; i++)
{
*p++ &= 0xFF;
}
}
------------------------------------------------------------------------------------------------
var uc = new UnsafeClass("Hello");
public unsafe struct MySctruct {
public int x;
public short Length;
public fixed byte Buffer[30]; // Allocate block of 30 bytes
}
public unsafe class UnsafeClass {
public MySctruct MySctruct;
public UnsafeClass(string s) {
MySctruct.Length = (short)s.Length;
fixed (byte* p = MySctruct.Buffer) {//fixed for pinning UnsafeClass
for (int i = 0; i < s.Length; i++) {
p[i] = (byte) s[i];
}
}
}
}
//I write it by myself, not verified
unsafe {
string myString = "Hello from managed code";
fixed (char* stringValuePointer = myString) {
for (int i = 0; i < myString.Length; i++) {
char* symbol = &stringValuePointer[i];
}
}
}
------------------------------------------------------------------------------------------------
Native and COM Interoperability:
http://www.pinvoke.net/ - wiki documentation on Win32 signatures
Call Native:
1) add attribute DllImport
2) add extern
[DllImport("user32.dll")]
static extern int MessageBox (IntPtr hWnd, string text, string caption, int type);
Unmanaged handles, for instance, can map to IntPtr, int, uint, long, or ulong
native string can be in defferent format, using MarshalAs we define format
[DllImport("...")]
static extern int Foo ( [MarshalAs (UnmanagedType.LPStr)] string s );
[DllImport("kernel32.dll")]
static extern int GetWindowsDirectory(StringBuilder sb, int maxChars); //http://www.pinvoke.net/default.aspx/kernel32.GetWindowsDirectory
must define struct or class:
[StructLayout(LayoutKind.Sequential)]
class/*struct*/ SystemTime
{
public ushort Year;
public ushort Month;
public ushort DayOfWeek;
public ushort Day; //actual name is not important, we can call it DayXXX.
public ushort Hour; //important are position and type
public ushort Minute;
public ushort Second;
public ushort Milliseconds;
}
[StructLayout (LayoutKind.Explicit)]
public struct NoteMessage
{
[FieldOffset(0)] public uint PackedMsg; // 4 bytes long
[FieldOffset(0)] public byte Channel; // FieldOffset also at 0
[FieldOffset(1)] public byte Note;
[FieldOffset(2)] public byte Velocity;
}
[DllImport("kernel32.dll")] static extern void GetSystemTime (SystemTime t); //SystemTime is class
[DllImport("kernel32.dll")] static extern void GetSystemTime (out SystemTime t); //SystemTime is struct
static extern void Foo ( [In]/*array is readonly*/ int[] array);
----------------------------------
CALLBACK (native calls managed):
BOOL EnumWindows (WNDENUMPROC lpEnumFunc, LPARAM lParam);
BOOL CALLBACK EnumWindowsProc (HWND hwnd, LPARAM lParam);
delegate bool EnumWindowsCallback (IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")] static extern int EnumWindows (EnumWindowsCallback hWnd, IntPtr lParam);
static bool PrintWindow (IntPtr hWnd, IntPtr lParam) {
Console.WriteLine (hWnd.ToInt64());
return true; //callback gets fired until callback returns false;
}
static void Main() {
EnumWindows (PrintWindow, IntPtr.Zero);
}
----------------------------------
Unmanaged heap: ????????????????///
Marshal.AllocHGlobal allocates memory on the unmanaged heap
Marshal.FreeHGlobal (new IntPtr (data));
----------------------------------
using (MemoryMappedFile mmFile = MemoryMappedFile.CreateNew ("MyShare", 1000))
using (MemoryMappedViewAccessor accessor = mmFile.CreateViewAccessor()) {
byte* pointer = null;
accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer);
void* root = pointer;
...
}
------------------------------------------------------------------------------------------------
COM:
COM interop types are automatically
generated proxy types that expose a .NET member for each COM member. The type
library importer tool (tlimp.exe) generates COM interop types from the command
line, based on a COM library that you choose, and compiles them into a COM interop
assembly.
1) add reference
2) COM Tab, Microsoft.Office.Interop.Excel
3) write code, use COM types almoust like usual (not always)
using System;
using Excel = Microsoft.Office.Interop.Excel;
class Program
{
static void Main()
{
var excel = new Excel.Application();
...
workBook.SaveAs (@"d:\temp.xlsx");
}
}
----------------
Make assembly COM public:
1) [assembly: Guid ("...")] // A unique GUID for the COM type library
2) use [ComVisible(true)] where is needed
3) The final step is to call the tlbexp.exe tool:
tlbexp.exe myLibrary.dll
This generates a COM type library (.tlb) file which you can then register and consume in COM applications.
------------------------------------------------------------------------------------------------
static checking - before compile
runtime checking - runtime
--------------------------------------------------
Preconditions:
- requires //DEBUG
Contract.Requires(!string.IsNullOrEmpty(name));
------------------------------------ DEBUG AND RELEASE
- requires<TException> //DEBUG + RELEASE
Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(name));
- if then ????????????????????? //DEBUG + RELEASE
if (name == null)
throw new ArgumentNullException("name");
Contract.EndContractBlock();
------------------------------------
----------------------------------------------------
Postconditions:
- Contract.Ensures(..) //DEBUG
- Contract.EnsuresOnThrow<T>(... if T is thrown condition should be true ...)
- Result and OldValue
Contract.OldValue(this.name) - value of name before method
Contract.Ensures(Contract.OldValue(this.name) != name);
Contract.Ensures(Contract.Result<string>() != null);
----------------------------------------------------
Object invariants
public class Person
{
private string name;
[ContractInvariantMethod]
private void Invariants()
{
//Ensures that name is correct everywhere for this class
Contract.Invariant(!string.IsNullOrEmpty(name));
Contract.Invatiant(Contract.ForAll(aliases, a => !string.IsNullOrEmpty(a)));
}
}
---------------------------------------------------
Not pre or post condition: (+gives info for static checking)
Contract.Assert(....) //throws an exception on violation //DEBUG
Contract.Assume(....) //do not thow an exception, but just gives info to static analis//NONE
---------------------------------------------------
With inheritance we can't add preconditions but we can add stronger post condition and we can add invatiants
Contract.ContractFailed += (sender, args) =>
{
string failureMessage = args.FailureKind + ": " + args.Message;
// Log failureMessage with unit testing framework:
// ...
args.SetUnwind();
};
+transition(opacity 0); ???????????????????????????????????????
body:hover {
background: black;
@include transition;
}
---------------------------------------------------
div:hover {
$default-box-shadow-blur: 30px;
@include single-box-shadow($blur: 30px);
}
---------------------------------------------------
div {
background: url('images/icon/phone.png');
background: image-url('icon/phone.png');
}
---------------------------------------------------
ICONS:
@import "xxxxxxx/*.png"
@include all-xxxxxxx-sprites; //xxxxxxx - folder name
=>it will generate sprite file and classes like .icon-xxxx for all images
@import "icon/*.png"
@include all-icon-sprites;
----------------------------
phone.png
phone_hover.png //_hover will generate rules
----------------------------
.icon-phone {
@include icon-sprite("phone");
}
---------------------------------------------------
http://habrastorage.org/storage2/ff2/f5a/16f/ff2f5a16fb49fe7e8f41d1dcabcedbdd.png
LinkedList
public class LinkedList{ public Node Head; public Node Tail; }
public class Node { public int Value; public Node Next; }
1) Adding new item we allocate just new node and change few pointers
(if it were array we would need move many items)
2) Removing element from the end requires enumerating the whole collection !!!!!!?????
--------------------------------
Doubly Linked List (System.Collections.Generic.LinkedList<T>)
public class Node { public int Value; public Node Next; public Node previous; }
1) removes LinkedList removing last element overhead
---------------------------------------------
Stack (LIFO)-last in first out (Stack<T>, Stack)
peek - get last from stack(from top)
pop - get and remove last from stack(from top)
push - add to the end(to the top)
---------------------------------------------
Queue (FIFO) - first in first out
peek
enqueue
dequeue
---------------------------------------------
Binaty Trees
Search binary tree
- node has two childs - left(smaller) and right(bigger)
- if we add equal to existing node then it goes to right(4 > 4)
- traversal: pre-order, in-order,post-order
---------------------------------------------
Hash Table (associative array)
---------------------------------------------
HashSet
-Uniot, Difference, ...
---------------------------------------------
Sets
---------------------------------------------
AVL Tree (self-balancing binary tree) - good for searching
- Right rotation
- left rotation
- right-left rotation
-left-right rotation
---------------------------------------------
SortedSet<T> - red-black tree
In Big-O notation, retrieval time by key is:
• O(1) for Hashtable, Dictionary, and OrderedDictionary
• O(log n) for SortedDictionary and SortedList
• O(n) for ListDictionary (and nondictionary types such as List<T>)
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Microsoft.CSharp.RuntimeBinder;
namespace ConsoleApplication11
{
class Program
{
static void Main(string[] args)
{
/*code that eventually results in an expression tree that describes the
operation, managed by a call site that the DLR will bind at runtime. The call site
essentially acts as an intermediary between caller and callee
call site is cached in a static field to avoid the cost of re-creating
it on each call
1) get cached call site
2) invoke call site Target
*/
/*dynamic din = new List<int>();
int count = din.Count;*/
object obj1 = (object) new List<int>();
if (SiteContainer.Site1 == null)
{
SiteContainer.Site1 = CallSite<Func<CallSite, object, int>>.Create(Binder.Convert(CSharpBinderFlags.None, typeof(int), typeof(Program)));
}
Func<CallSite, object, int> func = SiteContainer.Site1.Target;
CallSite<Func<CallSite, object, int>> callSite = SiteContainer.Site1;
if (SiteContainer.Site2 == null)
{
SiteContainer.Site2 = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None,
"Count",
typeof(Program),
(IEnumerable<CSharpArgumentInfo>)new CSharpArgumentInfo[1] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, (string)null) }
));
}
object obj2 = SiteContainer.Site2.Target((CallSite) Program.SiteContainer.Site2, obj1);
int num = func((CallSite) callSite, obj2);
Console.ReadKey();
}
[CompilerGenerated]
private static class SiteContainer
{
public static CallSite<Func<CallSite, object, int>> Site1;
public static CallSite<Func<CallSite, object, object>> Site2;
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using Microsoft.Scripting.Utils;
namespace DynamicConsoleApplication
{
class Program
{
[CompilerGenerated]
private static class SiteContainer
{
public static CallSite<Func<CallSite, object, int>> Site1;
public static CallSite<Func<CallSite, object, object>> Site2;
}
public class MyDynamicObject : CustomDynamicObject/*DynamicObject*/
{
public string Name { get; set; }
private Dictionary<string, object> _values = new Dictionary<string, object>();
public override IEnumerable<string> GetDynamicMemberNames()
{
return _values.Keys;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (_values.ContainsKey(binder.Name))
{
result = _values[binder.Name];
return true;
}
result = null;
return false;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_values[binder.Name] = value;
return true;
}
public override DynamicMetaObject GetMetaObject(System.Linq.Expressions.Expression parameter)
{
return base.GetMetaObject(parameter);
}
}
static void Main(string[] args)
{
/*dynamic din = new List<int>();
int count = din.Count;
COMPILES TO:
object obj1 = (object) new List<int>();
if (SiteContainer.Site1 == null)
{
SiteContainer.Site1 = CallSite<Func<CallSite, object, int>>.Create(Binder.Convert(CSharpBinderFlags.None, typeof(int), typeof(Program)));
}
Func<CallSite, object, int> func = SiteContainer.Site1.Target;
CallSite<Func<CallSite, object, int>> callSite = SiteContainer.Site1;
if (SiteContainer.Site2 == null)
{
SiteContainer.Site2 = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None,
"Count",
typeof(Program),
(IEnumerable<CSharpArgumentInfo>)new CSharpArgumentInfo[1] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, (string)null) }
));
}
object obj2 = SiteContainer.Site2.Target((CallSite) Program.SiteContainer.Site2, obj1);
int num = func((CallSite) callSite, obj2);*/
//#################################################################
/*Cannot be converted to object(and dynamic) pointers and TypedReference
dynamic foo = default(TypedReference);//ERROR
dynamic expando = new ExpandoObject();
expando.Hello = true;
*/
dynamic myDynamic = new MyDynamicObject() { Name = "staticName" };
//din["Name"] = "dynamicName";
myDynamic.Name = "staticName";
Console.WriteLine(myDynamic.Name == "staticName");
myDynamic.IsHello = true;
Console.WriteLine(myDynamic.IsHello == true);
Console.ReadKey();
}
}
#region DynamicObject
/// <summary>
/// Provides a simple class that can be inherited from to create an object with dynamic behavior
/// at runtime. Subclasses can override the various binder methods (GetMember, SetMember, Call, etc...)
/// to provide custom behavior that will be invoked at runtime.
///
/// If a method is not overridden then the DynamicObject does not directly support that behavior and
/// the call site will determine how the binding should be performed.
/// </summary>
[Serializable]
public class CustomDynamicObject : IDynamicMetaObjectProvider
{
/// <summary>
/// Enables derived types to create a new instance of DynamicObject. DynamicObject instances cannot be
/// directly instantiated because they have no implementation of dynamic behavior.
/// </summary>
protected CustomDynamicObject()
{
}
#region Public Virtual APIs
/// <summary>
/// Provides the implementation of getting a member. Derived classes can override
/// this method to customize behavior. When not overridden the call site requesting the
/// binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <param name="result">The result of the get operation.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
public virtual bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
return false;
}
/// <summary>
/// Provides the implementation of setting a member. Derived classes can override
/// this method to customize behavior. When not overridden the call site requesting the
/// binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <param name="value">The value to set.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
public virtual bool TrySetMember(SetMemberBinder binder, object value)
{
return false;
}
/// <summary>
/// Provides the implementation of deleting a member. Derived classes can override
/// this method to customize behavior. When not overridden the call site requesting the
/// binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
public virtual bool TryDeleteMember(DeleteMemberBinder binder)
{
return false;
}
/// <summary>
/// Provides the implementation of calling a member. Derived classes can override
/// this method to customize behavior. When not overridden the call site requesting the
/// binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <param name="args">The arguments to be used for the invocation.</param>
/// <param name="result">The result of the invocation.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
public virtual bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
result = null;
return false;
}
/// <summary>
/// Provides the implementation of converting the DynamicObject to another type. Derived classes
/// can override this method to customize behavior. When not overridden the call site
/// requesting the binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <param name="result">The result of the conversion.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
public virtual bool TryConvert(ConvertBinder binder, out object result)
{
result = null;
return false;
}
/// <summary>
/// Provides the implementation of creating an instance of the DynamicObject. Derived classes
/// can override this method to customize behavior. When not overridden the call site requesting
/// the binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <param name="args">The arguments used for creation.</param>
/// <param name="result">The created instance.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
public virtual bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result)
{
result = null;
return false;
}
/// <summary>
/// Provides the implementation of invoking the DynamicObject. Derived classes can
/// override this method to customize behavior. When not overridden the call site requesting
/// the binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <param name="args">The arguments to be used for the invocation.</param>
/// <param name="result">The result of the invocation.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
public virtual bool TryInvoke(InvokeBinder binder, object[] args, out object result)
{
result = null;
return false;
}
/// <summary>
/// Provides the implementation of performing a binary operation. Derived classes can
/// override this method to customize behavior. When not overridden the call site requesting
/// the binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <param name="arg">The right operand for the operation.</param>
/// <param name="result">The result of the operation.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
public virtual bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result)
{
result = null;
return false;
}
/// <summary>
/// Provides the implementation of performing a unary operation. Derived classes can
/// override this method to customize behavior. When not overridden the call site requesting
/// the binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <param name="result">The result of the operation.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
public virtual bool TryUnaryOperation(UnaryOperationBinder binder, out object result)
{
result = null;
return false;
}
/// <summary>
/// Provides the implementation of performing a get index operation. Derived classes can
/// override this method to customize behavior. When not overridden the call site requesting
/// the binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <param name="indexes">The indexes to be used.</param>
/// <param name="result">The result of the operation.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
public virtual bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
result = null;
return false;
}
/// <summary>
/// Provides the implementation of performing a set index operation. Derived classes can
/// override this method to custmize behavior. When not overridden the call site requesting
/// the binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <param name="indexes">The indexes to be used.</param>
/// <param name="value">The value to set.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
public virtual bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{
return false;
}
/// <summary>
/// Provides the implementation of performing a delete index operation. Derived classes
/// can override this method to custmize behavior. When not overridden the call site
/// requesting the binder determines the behavior.
/// </summary>
/// <param name="binder">The binder provided by the call site.</param>
/// <param name="indexes">The indexes to be deleted.</param>
/// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
public virtual bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes)
{
return false;
}
/// <summary>
/// Returns the enumeration of all dynamic member names.
/// </summary>
/// <returns>The list of dynamic member names.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
public virtual System.Collections.Generic.IEnumerable<string> GetDynamicMemberNames()
{
return new string[0];
}
#endregion
#region MetaDynamic
private sealed class MetaDynamic : DynamicMetaObject
{
/*internal*/public MetaDynamic(Expression expression, CustomDynamicObject value)
: base(expression, BindingRestrictions.Empty, value)
{
}
public override System.Collections.Generic.IEnumerable<string> GetDynamicMemberNames()
{
return Value.GetDynamicMemberNames();
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
if (IsOverridden("TryGetMember"))
{
return CallMethodWithResult("TryGetMember", binder, NoArgs, (e) => binder.FallbackGetMember(this, e));
}
return base.BindGetMember(binder);
}
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
{
if (IsOverridden("TrySetMember"))
{
return CallMethodReturnLast("TrySetMember", binder, NoArgs, value.Expression, (e) => binder.FallbackSetMember(this, value, e));
}
return base.BindSetMember(binder, value);
}
public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder)
{
if (IsOverridden("TryDeleteMember"))
{
return CallMethodNoResult("TryDeleteMember", binder, NoArgs, (e) => binder.FallbackDeleteMember(this, e));
}
return base.BindDeleteMember(binder);
}
public override DynamicMetaObject BindConvert(ConvertBinder binder)
{
if (IsOverridden("TryConvert"))
{
return CallMethodWithResult("TryConvert", binder, NoArgs, (e) => binder.FallbackConvert(this, e));
}
return base.BindConvert(binder);
}
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
{
// Generate a tree like:
//
// {
// object result;
// TryInvokeMember(payload, out result)
// ? result
// : TryGetMember(payload, out result)
// ? FallbackInvoke(result)
// : fallbackResult
// }
//
// Then it calls FallbackInvokeMember with this tree as the
// "error", giving the language the option of using this
// tree or doing .NET binding.
//
Fallback fallback = e => binder.FallbackInvokeMember(this, args, e);
var call = BuildCallMethodWithResult(
"TryInvokeMember",
binder,
CustomDynamicMetaObject.GetExpressions(args),
BuildCallMethodWithResult(
"TryGetMember",
new GetBinderAdapter(binder),
NoArgs,
fallback(null),
(e) => binder.FallbackInvoke(e, args, null)
),
null
);
return fallback(call);
}
public override DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args)
{
if (IsOverridden("TryCreateInstance"))
{
return CallMethodWithResult("TryCreateInstance", binder, CustomDynamicMetaObject.GetExpressions(args), (e) => binder.FallbackCreateInstance(this, args, e));
}
return base.BindCreateInstance(binder, args);
}
public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args)
{
if (IsOverridden("TryInvoke"))
{
return CallMethodWithResult("TryInvoke", binder, CustomDynamicMetaObject.GetExpressions(args), (e) => binder.FallbackInvoke(this, args, e));
}
return base.BindInvoke(binder, args);
}
public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
{
if (IsOverridden("TryBinaryOperation"))
{
return CallMethodWithResult("TryBinaryOperation", binder, CustomDynamicMetaObject.GetExpressions(new DynamicMetaObject[] { arg }), (e) => binder.FallbackBinaryOperation(this, arg, e));
}
return base.BindBinaryOperation(binder, arg);
}
public override DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder)
{
if (IsOverridden("TryUnaryOperation"))
{
return CallMethodWithResult("TryUnaryOperation", binder, NoArgs, (e) => binder.FallbackUnaryOperation(this, e));
}
return base.BindUnaryOperation(binder);
}
public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)
{
if (IsOverridden("TryGetIndex"))
{
return CallMethodWithResult("TryGetIndex", binder, CustomDynamicMetaObject.GetExpressions(indexes), (e) => binder.FallbackGetIndex(this, indexes, e));
}
return base.BindGetIndex(binder, indexes);
}
public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)
{
if (IsOverridden("TrySetIndex"))
{
return CallMethodReturnLast("TrySetIndex", binder, CustomDynamicMetaObject.GetExpressions(indexes), value.Expression, (e) => binder.FallbackSetIndex(this, indexes, value, e));
}
return base.BindSetIndex(binder, indexes, value);
}
public override DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes)
{
if (IsOverridden("TryDeleteIndex"))
{
return CallMethodNoResult("TryDeleteIndex", binder, CustomDynamicMetaObject.GetExpressions(indexes), (e) => binder.FallbackDeleteIndex(this, indexes, e));
}
return base.BindDeleteIndex(binder, indexes);
}
private delegate DynamicMetaObject Fallback(DynamicMetaObject errorSuggestion);
private readonly static Expression[] NoArgs = new Expression[0];
private static Expression[] GetConvertedArgs(params Expression[] args)
{
ReadOnlyCollectionBuilder<Expression> paramArgs = new ReadOnlyCollectionBuilder<Expression>(args.Length);
for (int i = 0; i < args.Length; i++)
{
paramArgs.Add(Expression.Convert(args[i], typeof(object)));
}
return paramArgs.ToArray();
}
/// <summary>
/// Helper method for generating expressions that assign byRef call
/// parameters back to their original variables
/// </summary>
private static Expression ReferenceArgAssign(Expression callArgs, Expression[] args)
{
ReadOnlyCollectionBuilder<Expression> block = null;
for (int i = 0; i < args.Length; i++)
{
ContractUtils.Requires(args[i] is ParameterExpression);
if (((ParameterExpression)args[i]).IsByRef)
{
if (block == null)
block = new ReadOnlyCollectionBuilder<Expression>();
block.Add(
Expression.Assign(
args[i],
Expression.Convert(
Expression.ArrayIndex(
callArgs,
Expression.Constant(i)
),
args[i].Type
)
)
);
}
}
if (block != null)
return Expression.Block(block);
else
return Expression.Empty();
}
/// <summary>
/// Helper method for generating arguments for calling methods
/// on DynamicObject. parameters is either a list of ParameterExpressions
/// to be passed to the method as an object[], or NoArgs to signify that
/// the target method takes no object[] parameter.
/// </summary>
private static Expression[] BuildCallArgs(DynamicMetaObjectBinder binder, Expression[] parameters, Expression arg0, Expression arg1)
{
if (!object.ReferenceEquals(parameters, NoArgs))
return arg1 != null ? new Expression[] { Constant(binder), arg0, arg1 } : new Expression[] { Constant(binder), arg0 };
else
return arg1 != null ? new Expression[] { Constant(binder), arg1 } : new Expression[] { Constant(binder) };
}
private static ConstantExpression Constant(DynamicMetaObjectBinder binder)
{
Type t = binder.GetType();
while (!t.IsVisible)
{
t = t.BaseType;
}
return Expression.Constant(binder, t);
}
/// <summary>
/// Helper method for generating a MetaObject which calls a
/// specific method on Dynamic that returns a result
/// </summary>
private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback)
{
return CallMethodWithResult(methodName, binder, args, fallback, null);
}
/// <summary>
/// Helper method for generating a MetaObject which calls a
/// specific method on Dynamic that returns a result
/// </summary>
private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback, Fallback fallbackInvoke)
{
//
// First, call fallback to do default binding
// This produces either an error or a call to a .NET member
//
DynamicMetaObject fallbackResult = fallback(null);
var callDynamic = BuildCallMethodWithResult(methodName, binder, args, fallbackResult, fallbackInvoke);
//
// Now, call fallback again using our new MO as the error
// When we do this, one of two things can happen:
// 1. Binding will succeed, and it will ignore our call to
// the dynamic method, OR
// 2. Binding will fail, and it will use the MO we created
// above.
//
return fallback(callDynamic);
}
/// <summary>
/// Helper method for generating a MetaObject which calls a
/// specific method on DynamicObject that returns a result.
///
/// args is either an array of arguments to be passed
/// to the method as an object[] or NoArgs to signify that
/// the target method takes no parameters.
/// </summary>
private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, DynamicMetaObject fallbackResult, Fallback fallbackInvoke)
{
if (!IsOverridden(methodName))
{
return fallbackResult;
}
//
// Build a new expression like:
// {
// object result;
// TryGetMember(payload, out result) ? fallbackInvoke(result) : fallbackResult
// }
//
var result = Expression.Parameter(typeof(object), null);
ParameterExpression callArgs = methodName != "TryBinaryOperation" ? Expression.Parameter(typeof(object[]), null) : Expression.Parameter(typeof(object), null);
var callArgsValue = GetConvertedArgs(args);
var resultMO = new DynamicMetaObject(result, BindingRestrictions.Empty);
// Need to add a conversion if calling TryConvert
if (binder.ReturnType != typeof(object))
{
Debug.Assert(binder is ConvertBinder && fallbackInvoke == null);
var convert = Expression.Convert(resultMO.Expression, binder.ReturnType);
// will always be a cast or unbox
Debug.Assert(convert.Method == null);
// Prepare a good exception message in case the convert will fail
string convertFailed = Strings.DynamicObjectResultNotAssignable(
"{0}",
this.Value.GetType(),
binder.GetType(),
binder.ReturnType
);
var checkedConvert = Expression.Condition(
Expression.TypeIs(resultMO.Expression, binder.ReturnType),
convert,
Expression.Throw(
Expression.New(typeof(InvalidCastException).GetConstructor(new Type[] { typeof(string) }),
Expression.Call(
typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object) }),
Expression.Constant(convertFailed),
Expression.Condition(
Expression.Equal(resultMO.Expression, Expression.Constant(null)),
Expression.Constant("null"),
Expression.Call(
resultMO.Expression,
typeof(object).GetMethod("GetType")
),
typeof(object)
)
)
),
binder.ReturnType
),
binder.ReturnType
);
resultMO = new DynamicMetaObject(checkedConvert, resultMO.Restrictions);
}
if (fallbackInvoke != null)
{
resultMO = fallbackInvoke(resultMO);
}
var callDynamic = new DynamicMetaObject(
Expression.Block(
new[] { result, callArgs },
methodName != "TryBinaryOperation" ? Expression.Assign(callArgs, Expression.NewArrayInit(typeof(object), callArgsValue)) : Expression.Assign(callArgs, callArgsValue[0]),
Expression.Condition(
Expression.Call(
GetLimitedSelf(),
typeof(CustomDynamicObject).GetMethod(methodName),
BuildCallArgs(
binder,
args,
callArgs,
result
)
),
Expression.Block(
methodName != "TryBinaryOperation" ? ReferenceArgAssign(callArgs, args) : Expression.Empty(),
resultMO.Expression
),
fallbackResult.Expression,
binder.ReturnType
)
),
GetRestrictions().Merge(resultMO.Restrictions).Merge(fallbackResult.Restrictions)
);
return callDynamic;
}
/// <summary>
/// Helper method for generating a MetaObject which calls a
/// specific method on Dynamic, but uses one of the arguments for
/// the result.
///
/// args is either an array of arguments to be passed
/// to the method as an object[] or NoArgs to signify that
/// the target method takes no parameters.
/// </summary>
private DynamicMetaObject CallMethodReturnLast(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Expression value, Fallback fallback)
{
//
// First, call fallback to do default binding
// This produces either an error or a call to a .NET member
//
DynamicMetaObject fallbackResult = fallback(null);
//
// Build a new expression like:
// {
// object result;
// TrySetMember(payload, result = value) ? result : fallbackResult
// }
//
var result = Expression.Parameter(typeof(object), null);
var callArgs = Expression.Parameter(typeof(object[]), null);
var callArgsValue = GetConvertedArgs(args);
var callDynamic = new DynamicMetaObject(
Expression.Block(
new[] { result, callArgs },
Expression.Assign(callArgs, Expression.NewArrayInit(typeof(object), callArgsValue)),
Expression.Condition(
Expression.Call(
GetLimitedSelf(),
typeof(CustomDynamicObject).GetMethod(methodName),
BuildCallArgs(
binder,
args,
callArgs,
Expression.Assign(result, Expression.Convert(value, typeof(object)))
)
),
Expression.Block(
ReferenceArgAssign(callArgs, args),
result
),
fallbackResult.Expression,
typeof(object)
)
),
GetRestrictions().Merge(fallbackResult.Restrictions)
);
//
// Now, call fallback again using our new MO as the error
// When we do this, one of two things can happen:
// 1. Binding will succeed, and it will ignore our call to
// the dynamic method, OR
// 2. Binding will fail, and it will use the MO we created
// above.
//
return fallback(callDynamic);
}
/// <summary>
/// Helper method for generating a MetaObject which calls a
/// specific method on Dynamic, but uses one of the arguments for
/// the result.
///
/// args is either an array of arguments to be passed
/// to the method as an object[] or NoArgs to signify that
/// the target method takes no parameters.
/// </summary>
private DynamicMetaObject CallMethodNoResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback)
{
//
// First, call fallback to do default binding
// This produces either an error or a call to a .NET member
//
DynamicMetaObject fallbackResult = fallback(null);
var callArgs = Expression.Parameter(typeof(object[]), null);
var callArgsValue = GetConvertedArgs(args);
//
// Build a new expression like:
// if (TryDeleteMember(payload)) { } else { fallbackResult }
//
var callDynamic = new DynamicMetaObject(
Expression.Block(
new[] { callArgs },
Expression.Assign(callArgs, Expression.NewArrayInit(typeof(object), callArgsValue)),
Expression.Condition(
Expression.Call(
GetLimitedSelf(),
typeof(CustomDynamicObject).GetMethod(methodName),
BuildCallArgs(
binder,
args,
callArgs,
null
)
),
Expression.Block(
ReferenceArgAssign(callArgs, args),
Expression.Empty()
),
fallbackResult.Expression,
typeof(void)
)
),
GetRestrictions().Merge(fallbackResult.Restrictions)
);
//
// Now, call fallback again using our new MO as the error
// When we do this, one of two things can happen:
// 1. Binding will succeed, and it will ignore our call to
// the dynamic method, OR
// 2. Binding will fail, and it will use the MO we created
// above.
//
return fallback(callDynamic);
}
/// <summary>
/// Checks if the derived type has overridden the specified method. If there is no
/// implementation for the method provided then Dynamic falls back to the base class
/// behavior which lets the call site determine how the binder is performed.
/// </summary>
private bool IsOverridden(string method)
{
var methods = Value.GetType().GetMember(method, MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance);
foreach (MethodInfo mi in methods)
{
//########################################################################################################
return true;
/*if (mi.DeclaringType != typeof(DynamicObject) && mi.GetBaseDefinition().DeclaringType == typeof(DynamicObject))
{
return true;
}*/
}
return false;
}
/// <summary>
/// Returns a Restrictions object which includes our current restrictions merged
/// with a restriction limiting our type
/// </summary>
private BindingRestrictions GetRestrictions()
{
Debug.Assert(Restrictions == BindingRestrictions.Empty, "We don't merge, restrictions are always empty");
//return BindingRestrictions.GetTypeRestriction(this);
DynamicMetaObject obj = this;
if (obj.Value == null && obj.HasValue)
return BindingRestrictions.GetInstanceRestriction(obj.Expression, (object)null);
else
return BindingRestrictions.GetTypeRestriction(obj.Expression, obj.LimitType);
}
/// <summary>
/// Returns our Expression converted to DynamicObject
/// </summary>
private Expression GetLimitedSelf()
{
// Convert to DynamicObject rather than LimitType, because
// the limit type might be non-public.
if (TypeUtils.AreEquivalent(Expression.Type, typeof(CustomDynamicObject)))
{
return Expression;
}
return Expression.Convert(Expression, typeof(CustomDynamicObject));
}
private new CustomDynamicObject Value
{
get
{
return (CustomDynamicObject)base.Value;
}
}
// It is okay to throw NotSupported from this binder. This object
// is only used by DynamicObject.GetMember--it is not expected to
// (and cannot) implement binding semantics. It is just so the DO
// can use the Name and IgnoreCase properties.
private sealed class GetBinderAdapter : GetMemberBinder
{
internal GetBinderAdapter(InvokeMemberBinder binder)
: base(binder.Name, binder.IgnoreCase)
{
}
public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
{
throw new NotSupportedException();
}
}
}
#endregion
#region IDynamicMetaObjectProvider Members
/// <summary>
/// The provided MetaObject will dispatch to the Dynamic virtual methods.
/// The object can be encapsulated inside of another MetaObject to
/// provide custom behavior for individual actions.
/// </summary>
public virtual DynamicMetaObject GetMetaObject(Expression parameter)
{
return new MetaDynamic(parameter, this);
}
#endregion
}
#endregion
#region Copy-pasted UTILS
public static class TypeUtils
{
internal static bool AreEquivalent(Type t1, Type t2)
{
if (!(t1 == t2))
return t1.IsEquivalentTo(t2);
else
return true;
}
}
internal static class Strings
{
internal static string DynamicObjectResultNotAssignable(object p0/*"{0}"*/, object p1, object p2, object p3)
{
return "HELLO";
//return SR.GetString("DynamicObjectResultNotAssignable", p0, p1, p2, p3);
}
}
internal class CustomDynamicMetaObject
{
internal static Expression[] GetExpressions(DynamicMetaObject[] objects)
{
ContractUtils.RequiresNotNull((object)objects, "objects");
Expression[] expressionArray = new Expression[objects.Length];
for (int index = 0; index < objects.Length; ++index)
{
DynamicMetaObject dynamicMetaObject = objects[index];
ContractUtils.RequiresNotNull((object)dynamicMetaObject, "objects");
Expression expression = dynamicMetaObject.Expression;
ContractUtils.RequiresNotNull((object)expression, "objects");
expressionArray[index] = expression;
}
return expressionArray;
}
}
#endregion
}
http://jade-lang.com/tutorial/
Text:
1)
div Hello
2)
div.
one
one
3)
div
| one one
| two two
------------------------------------------------
Attribute:
div(data-info="hello", yo="yo")
div.myClass
div#myId
------------------------------------------------
If
var user = null;// { name: 'John' }
if user
div.welcomebox
// Filtered inline output
p.
Welcome, #{user.name}
else
div.loginbox
form(name="login", action="/login", method="post")
input(type="text", name="user")
input(type="password", name="pass")
input(type="submit", value="login")
------------------------------------------------
lock (this) { } ===>
Boolean lockTaken = false; //lockTaken pattern
try {
Monitor.Enter(this, ref lockTaken);
// This code has exclusive access to the data...
}
finally {
if (lockTaken) Monitor.Exit(this);
}
--------------------------------------------------------
Use Monitor.Wait and Monitor.Pulse(PulseAll) for blocking thread until custom condition is met.
Monitor.Pulse is asynchronous so there can be a delay beetwean pulse and wait
http://www.codeproject.com/Articles/28785/Thread-synchronization-Wait-and-Pulse-demystified
using System;
using System.Threading;
namespace CustomResetEventWithMonitorConsoleApplication
{
class Program
{
static CustomAutoResetEvent customAutoResetEvent = new CustomAutoResetEvent();
static void Main(string[] args)
{
new Thread(SecondThread).Start();
Console.ReadLine(); // Wait for user to hit Enter
customAutoResetEvent.Set();
Console.ReadKey();
}
static void SecondThread()
{
customAutoResetEvent.WaitOne();
Console.WriteLine("Second thread continue after pulse from first thread");
}
}
public class CustomAutoResetEvent
{
readonly object _locker = new object();
bool _signal;
void WaitOne()
{
lock (_locker)
{
while (!_signal/*blocking condition*/) { // about three more times then Pulse
Monitor.Wait (_locker); // Lock is released while we’re waiting
}
_signal = false;
}
}
void Set() {
lock (_locker) { // Let's now wake up the thread by
//alter the field(s) or data that might impact the blocking condition(s)
_signal = true;
Monitor.Pulse (_locker); // 120ns
}
}
void Reset() { lock (_locker) _signal = false; }
}
public class CustomManualResetEvent
{
readonly object _locker = new object();
bool _signal;
void WaitOne()
{
lock (_locker)
{
while (!_signal) Monitor.Wait(_locker);
}
}
void Set()
{
lock (_locker) { _signal = true; Monitor.PulseAll(_locker); }
}
void Reset() { lock (_locker) _signal = false; }
}
public class Countdown
{
object _locker = new object ();
int _value;
public Countdown() { }
public Countdown (int initialCount) { _value = initialCount; }
public void Signal() { AddCount (-1); }
public void AddCount (int amount)
{
lock (_locker)
{
_value += amount;
if (_value <= 0) Monitor.PulseAll (_locker);
}
}
public void Wait()
{
lock (_locker)
while (_value > 0) {
Monitor.Wait (_locker);
}
}
}
}
--------------------------------------------------------------------------
NoSQL Databases:
- document databases
- graph stores
- key-value stores
- wide column stores
+ more scalabele (horizontal scaling)
+ bette performance
+ faster code development
+ scale-out architecture instead of expensive, monolitic architecture
+ dynamic schema
+ less administrator time is needed
+ AUTO-SHARDING -> no transactions, data spreaded on manu machines
+ often caching is integrated into NoSQL
+ price
+ object oriented API (no sql statements)
+ many different specialized noSql db types
_______________________________________________________________________
MapReduce http://en.wikipedia.org/wiki/MapReduce http://docs.mongodb.org/manual/core/map-reduce/
is a data processing paradigm for condensing large volumes of data into useful aggregated results
Map() - performs filtering and sorting
(K1, V1) -> list(K2, V2) - independent record tarnsformations
Reduce() - performs a summary operation
(K2, list(V2)) -> list(K3, V3) - aggreagate results from map phase
Stages:
- Map
The master node takes the input, divides it into smaller sub-problems, and distributes them to worker nodes. A worker node may do this again in turn, leading to a multi-level tree structure. The worker node processes the smaller problem, and passes the answer back to its master node.
- Shuffle
the Map output to the Reduce processors
- Reduce
The master node then collects the answers to all the sub-problems and combines them in some way to form the output – the answer to the problem it was originally trying to solve.
_______________________________________________________________________
Apache Hadoop (free) - yahoo
Apache Cassandra (payed) - facebook
_______________________________________________________________________
MONGODB
comment = { author: "eliot", date: new Date(), text: "grate post" }
post = { date: new Date(), text: "my blog post..", tags: ["mongoDB", "intro"] }
aug_1 = new Date(2010, 7, 1);
db.posts.save(post);
db.test.save({a: 1});
db.posts.find({ date: {$gt: aug_1}});
db.posts.find({"comments.author": "eliot"})
db.test.find({a: 1});
db.posts.find()
.sort({date: -1})
.limit(10);
db.posts.update({ _id: post.id}, {$push: {comments: comment}})
db.posts.ensureIndex({tags: 1})
db.posts.ensureIndex({"comments.author": 1})
_______________________________________________________________________
APPDOMAIN:
//AppDomainSetup setup = new AppDomainSetup() { ApplicationBase = @"c:\MyBaseFolder" };
//AppDomain newDomain = AppDomain.CreateDomain("New Domain", null, setup);
AppDomain newDomain = AppDomain.CreateDomain("New Domain");
newDomain.ExecuteAssembly("test.exe");
newDomain.ProcessExit +=(sender,e)=>{}; //when process terminates it fire event on all domains, handler has 2seconds
AppDomain.Unload(newDomain);
AppDomain.MonitoringIsEnabled = true;
AppDomain.CurrentDomain.AssemblyResolve += FindAssembly;
static Assembly FindAssembly (object sender, ResolveEventArgs args)
{
string fullyQualifiedName = args.Name;
Assembly a = Assembly.LoadFrom (...);
return a;
}
----------------------------------------------------------------------------------
RESOLUTION CONTEXT:
If you mix the two approaches, you will usually end up with two copies of the assembly
in memory, because the CLR considers each to be a different “resolution
context.”
var foo = new Foo();
var assembly = Assembly.LoadFrom(@"F:\PROJECTS\Experiments\Algorithms\bin\Debug\Algorithms.dll");
var fooType = assembly.GetType("Algorithms.Foo");
bool typesAreDifferent = Activator.CreateInstance(fooType).GetType() != typeof(Foo);
----------------------------------------------------------------------------------
COMMUNICATE WITH OTHER DOMAIN:
1) newDomain.SetData("myData", new MySerializableClass());//share date between domains
2) newDomain.DoCallBack (new CrossAppDomainDelegate (MyStaticClass.SayHello));
This makes the delegate “domain-agnostic” or agile. It can run in any domain, and in the same way, as there’s nothing tying it
to the original domain. If delegate reference to instance then CRL will try to apply remoting semantics
3) instantiate objects(must ingerit MarshalByRefObject) in the other domain via a proxy. This is called Remoting.
public class Foo : MarshalByRefObject {
public string SayHello() {
//method can marshal result:
//by reference) if method returns MarshalByRefObject instance references then it will be converted to transparent proxies
//by value) [Serializable] and ISerializable objects will be passed by serialized value
//
return "Hello from " + AppDomain.CurrentDomain.FriendlyName;
}
public override object InitializeLifetimeService() {
return null; // This ensures the object lasts for as long as the client(Default domain) wants it
// we can do this because we know that if default domain will crash - it does the whole process
/*
The default behavior is for remotely created objects to self-destruct after five minutes of nonuse.
*/
}
}
//ITextPlugin plugin = (ITextPlugin) domain.CreateInstanceFromAndUnwrap("AllCapitals.dll", "Plugin.Extensions.AllCapitals");
//object foo = newDomain.CreateInstanceAndUnwrap("MyAssembly", "MyClass");
Foo foo = (Foo)newDomain.CreateInstanceAndUnwrap(typeof(Foo).Assembly.FullName, typeof(Foo).FullName);
Console.WriteLine(foo.SayHello());
----------------------------------------------------------------------------------
OPTIMIZATIONS:
[LoaderOptimization(LoaderOptimization.MultiDomainHost)]
static void Main(string[] args) {}
This instructs the CLR to load GAC assemblies domain-neutral, so native images are honored and JIT images shared across application domains.
[LoaderOptimization(LoaderOptimization.MultiDomain)] //works with NGened signed assemblies
static void Main(string[] args) {}
all assemblies to be loaded domain-neutral (excluding those loaded outside the normal assembly resolution mechanism).
----------------------------------------------------------------------------------
SOLID:
S - Single responsibility principle
a class should have only a single responsibility.
O - Open/closed principle
“software entities … should be open for extension, but closed for modification”.
L - Liskov substitution principle
“objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program”
I - Interface segregation principle
“many client-specific interfaces are better than one general-purpose interface.”
D - Dependency inversion principle
one should “Depend upon Abstractions. Do not depend upon concretions
-------------------------------------
http://aviadezra.blogspot.com/2009/05/uml-association-aggregation-composition.html
UML:
line (may be with two arrow lines) - association - there is some kind of a link or dependency
or it hosld reference or it has it in method params
line with trianlge - generalization- inherit
line with rhomb - aggregation - B is part of A, but only logically
(Martin Fauler said do not use)
line with black rhomb - composition - B physically contained in A
and they init and delete together
-------------------------------------------------------------------------
OOP basic principles:
1) abstraction - to represent the essential feature without representing the back ground details
2) encapsulation - enclosing related operations and data in a capsule
3) inheritance - is process of object reusability
4) polymorphism - Polymorphism allows two or more objects respond to the same message
(means one name many forms)
--------------------------------------------------------------------------
public class DisposePatternClass : IDisposable
{
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
//dispose managed resources(non-finalizable logic)
}
//dispose unmanaged resources
disposed = true;
base.Dispose(disposing); // if we have
}
}
~MyClass() { Dispose(false); }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
class AlbahariDisposable : IDisposable {
public void Dispose() { // NOT virtual
Dispose (true);
GC.SuppressFinalize (this); // Prevent finalizer from running.
}
protected virtual void Dispose (bool disposing) {
if (disposing) {
// Call Dispose() on other objects owned by this instance.
// You can reference other finalizable objects here.
// ...
}
// Release unmanaged resources owned by (just) this object.
// ...
//not reference other objects with finalizers (because such objects
//may themselves have been finalized and so be in an unpredictable state)
}
˜`AlbahariDisposable() {
Dispose (false);
}
}
--------------------------------------------------------------------------
public sealed class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object();
Singleton() { }
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
http://csharpindepth.com/articles/general/singleton.aspx
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit //typeof(Singleton).Attributes.HasFlag(TypeAttributes.BeforeFieldInit);
//http://csharpindepth.com/articles/general/BeforeFieldInit.aspx
//If we do not specify static constructor then CRL can pick time when call type initialization by itself, it can be made earlier or event later
//If type has no static constructor then type is marked as beforefieldinit and CRL call initialization when it wants.
static Singleton() { }
private Singleton() { }
public static Singleton Instance
{
get { return instance; }
}
}
public sealed class Singleton
{
//INFO: LazyInitializer.EnsureInitialized(ref name, () => "Hello Lazy");
private static readonly Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton() { }
}
internal sealed class RichterDoubleLockSingleton {
private static readonly Object s_lock = new Object();
private static Singleton s_value = null;
private Singleton() {
// Code to initialize the one Singleton object goes here...
}
public static Singleton GetSingleton() {
if (s_value != null) return s_value;
Monitor.Enter(s_lock);
if (s_value == null) {
Singleton temp = new Singleton();
Volatile.Write(ref s_value, temp);//make sure publish after ctor was called
}
Monitor.Exit(s_lock);
return s_value;
}
}
internal sealed class RichterSingleton {
1) CLR ensure that class ctor thread safe, which creates instance of the object
2) downside - singleton created when any memeber of a class is first accessed
private static Singleton s_value = new Singleton();
private Singleton() {
// Code to initialize the one Singleton object goes here...
}
public static Singleton GetSingleton() { return s_value; }
}
internal sealed class RichterSingleton {
1) can create few instances but published will be only one, other will be GC'd
private static Singleton s_value = null;
private Singleton() {
// Code to initialize the one Singleton object goes here...
}
public static Singleton GetSingleton() {
if (s_value != null) return s_value;
Singleton temp = new Singleton();
Interlocked.CompareExchange(ref s_value, temp, null);
return s_value;
}
}
--------------------------------------------------------------------------
Patterns:
1) Creational Patterns
- Abstract Factory <Create instances of classes belonging to different families>
interface IToyFactory, class WoodenToyFactory, class TedyToyFactory
DbProviderFactory, SqlClientFactory
- Builder <Separate representation and object construction>
abstract LaptopBuilder, class GamingLaptopBuilder, class TripLaptopBuilder, director - class BuyLaptop
- Factory method <Create instances of derived classes>
ILogger GetLogger(logerType){}
- Prototype <Clone or copy initialized instances> var nextParty = GetBeerParty().Clone();
- Singleton <Class with only one single possible instance>
2) Structural Patterns
- Adapter <Match interfaces of classes with different interfaces>
class Adapter : INewElectricitySystem {
private readonly OldElectricitySystem _adaptee; ...
}
- Bridge <Decouple an abstraction from its implementation so that the two can vary independently.>
abstract class AbstractionClass { //IBuildingCompany
...IDoSomething ImplementationClass <---- BRIDGE//IWallCreator
}
class ConcreteImplementation : ImplementationClass {}
class ConcreteAbstraction : AbstractionClass {}
- Composite <Simple and composite objects tree>
interface IEmpoyee - all tree node implement it
class Supervisor : IEmpoyee
class Worker : IEmpoyee
- Decorator <Dynamically add responsibilities to objects>
class Car
class SpeedCar : Car { SpeedCar = wrapper
public SpeedCar(Car car) {}
void NewExtraMethod(){} <--- add new FUNCTIONALITY
}
- Facade <Class that represents subclasses and subsystems>
- Flyweight <Minimize memory usage by sharing as much data as possible with similar objects>
- Proxy <Object that represents another object>
3) Behavioral Patterns
- Chain of Responsibility
<Pass requests between command and processing objects within a chain of objects>
var girlFriend = new GirlFriend(null);//she last in chain
var me = new Me(girlFriend); //if I doesn't like it - i give it to girl
var bestFriend = new BestFriend(me); //if he doesn't like it - he gives it me
bestFriend.HandleFood(cappuccino1); //start chain
- Command <Encapsulate a method call as an object containing all necessary information>
public interface ICommand { void Execute(); }
- Interpreter <Include language elements and evaluate sentences in a given language>
abstract class AbstractExpression { public abstract void Interpret(Context c); }
class TerminalExpression, class NonterminalExpression
- Iterator <Give sequential access to elements in a collection>
Enumerator e = list.GetEnumerator();
while (e.MoveNext()) { e.Current; /*e.Reset();*/ }
interface IEnumerable<out T> : IEnumerable { new IEnumerator<T> GetEnumerator(); }
- Mediator <Encapsulates and simplifies communication between objects>
brain is mediator between coleages(head, leg, face, body...)
leg shoudn't know about face
- Memento <Undo modifications and restore an object to its initial state>
class GameMemento(with class GameState instance inside),
class GameOriginator { Play, Save, LoadGame}
class Caretaker { F5, F9, ShootSomeone} (with Stack<GameMemento>)
- Observer <Notify dependent objects of state changes>
interface IObserver { void Update(ISubject subject); } <-- EVENTS implement
interface ISubject { Attach(IObserver o); Detach(IObserver o); Notify(); }
- State <Change object behavior depending on its state>
class Order { private State }, abstract Class State,
class Cancelled : State, class Granted : State { void AddProduct, void Ship... }
- Strategy <Encapsulate algorithms within a class and make them interchangeable>
class MySelf { IWearingStrategy _strategy; ... stratery.GetClothes(); ... }
class SunShineWearingStrategy : IWearingStrategy ...
- Template Method <Define an algorithm skeleton and delegate algorithm steps to subclasses so that they may be overridden>
class Searcher { virtual void A, virtual void B, Search { A(); B(); } }
class ImportantSearcher : Searcher { override B }
new ImportantSearcher().Search(); // Search - template method
class with method that use many virtual methods for overriding
- Visitor <Add new operations to classes without modifying them>
interface IVisitor { void Visit(OfficeBuilding); void Visit(Floor) }
interface IElement { void Accept(IVisitor); }
class ElectricitySystemValidator: IVisitor
class Floor : IElement, class OfficeBuilding : IElement
--------------------------------------------------------------------------
Creational Patterns
- Abstract Factory Pattern: Create instances of classes belonging to different families
- Builder Pattern: Separate representation and object construction
- Factory Method Pattern: Create instances of derived classes
- Prototype Pattern: Clone or copy initialized instances
- Singleton Pattern: Class with only one single possible instance
Structural Patterns
- Adapter Pattern: Match interfaces of classes with different interfaces
- Bridge Pattern:: Separate implementation and object interfaces
- Composite: Simple and composite objects tree
- Decorator: Dynamically add responsibilities to objects
- Facade: Class that represents subclasses and subsystems
- Flyweight: Minimize memory usage by sharing as much data as possible with similar objects
- Proxy: Object that represents another object
Behavioral Patterns
- Chain of Responsibility: Pass requests between command and processing objects within a chain of objects
- Command: Encapsulate a method call as an object containing all necessary information
- Interpreter: Include language elements and evaluate sentences in a given language
- Iterator: Give sequential access to elements in a collection
- Mediator: Encapsulates and simplifies communication between objects
- Memento: Undo modifications and restore an object to its initial state
- Observer: Notify dependent objects of state changes
- State: Change object behavior depending on its state
- Strategy: Encapsulate algorithms within a class and make them interchangeable
- Template Method: Define an algorithm skeleton and delegate algorithm steps to subclasses so that they may be overridden
- Visitor: Add new operations to class hierarchy without modifying them
abstract class PersonVisitor<T> { //DYNAMIC VISITOR:
public T DynamicVisit (Person p) { return Visit ((dynamic)p); }
protected abstract T Visit (Person p);
protected virtual T Visit (Customer c) { return Visit ((Person) c); }
protected virtual T Visit (Employee e) { return Visit ((Person) e); }
}
-------------------------------------------------------------------------
1) First try Volatile, Interlocked
2) Try this patter to perform rich operations
3) then use the kernel object constructs if you want to synchronize threads that are running in different AppDomains or processes.
4) use the Monitor class with a private field
5) avoid using recursive locks
6) avoid releasing a lock in a finally block because entering and leaving exception-handling blocks incurs a performance hit,
Interlocked Pattern ("The Interlocked Anything Pattern")
public static Int32 Maximum(ref Int32 target, Int32 value) {
Int32 currentVal = target, startVal, desiredVal;
// Don't access target in the loop except in an attempt
// to change it because another thread may be touching it
do {
// Record this iteration's starting value
startVal = currentVal;
// Calculate the desired value in terms of startVal and value
desiredVal = Math.Max(startVal, value);
// NOTE: the thread could be preempted here!
// if (target == startVal) target = desiredVal
// Value prior to potential change is returned
currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal);
// If the starting value changed during this iteration, repeat
} while (startVal != currentVal);
// Return the maximum value when this thread tried to set it
return desiredVal;
}
----------------------------------------------------------------------------
$myColor: #ffeedd;
$myColor: black;
$size: 4px;
$font: Helverica, sans-serif;
$prefix: true !default;
font-size: 10px + 8px;
font-size: 10px + 8;
color: lighten($color, 10%);
color: darken($color, 10%);
color: saturate($color, 10%);
color: desaturate($color, 10%);
color: fade_in($color, .1);
color: fade_out($color, .1);
color: invert($color);
$quoted: quote($sometext);
$unquoted: unquote($sometext);
$value: if(true, $color1, $color2);
----------------------------------------------
INTERPOLATION:
$root: "/images/";
#form {
background: url("#{$root}background.jpg");
background: url($root + "background.jpg");
}
$name: "my-class";
.#{$name} {
color: blue;
}
----------------------------------------------
RULES:
div {
color: white;
span {
color: black;
}
&:hover {
}
}
----------------------------------------------
PROPERTIES:
.button {
font: {
family: Verdana, Helvetica, sans-serif;
size: 14px;
}
}
.button {
font-family: Verdana, Helvetica, sans-serif;
font-size: 14px;
}
----------------------------------------------
DIRECTIVES:
---------------------------------
@import "header";
#main {
@import "header";
}
---------------------------------
.button {
color: black;
}
.submit-button {
@extend .button; //@extend a:hover
border: 1px black solid;
}
---------------------------------
@mixin font-large($size: 5px) {
font: {
$size;
family: sans-serif;
}
}
#form {
@include font-large(14px);
}
---------------------------------
@app-width: 900px;
@function column-width($cols) {
@return (@app-width / $cols) - ($cols * 5px);
}
.col2 {
width: column-width(2);
}
----------------------------------------------
CONTROL DIRECTIVES:
---------------------------------
h1 {
@if $size > 14px {
color: blue;
}
@else if $size < 14px {
color: red;
}
@else {
color: green;
}
}
---------------------------------
@for $col from 1 through 4 { //"through"(include) or "to"(not inclusive)
.col#{$col} {
width: $page-width / $col;
}
}
---------------------------------
@each $item in first, second, third, fourth {
.#{$item} {
background-url: url(/images/#{$item}.jpg);
}
}
---------------------------------
$i: 1;
@while $i < 5 {
h#{$i} {
font-size: $i * 4px;
$i: $i + 1;
}
}
----------------------------------------------
paramete sniffing http://www.brentozar.com/archive/2013/06/the-elephant-and-the-mouse-or-parameter-sniffing-in-sql-server/
http://technet.microsoft.com/en-us/library/ms187713.aspx
SELECT * FROM sys.dm_exec_cached_plans
SELECT * FROM sys.dm_exec_sql_text
---- Execution Plan Types: --------------------
1) Estimated Execution Plan
–Created without ever running the query
–Uses statistics for estimation
–Good for long running query tuning
2) Actual Execution Plan
–Created when the actual query runs
–Uses the real data
3) Textual Execution Plan
–Depricated in further versions of SQL Server
4) XML based Execution Plan
–Very good for further analysis
–Can be queried
5) Graphic Execution Plan
–Uses internally the XML based Execution Plan
They can be different
–Statistics out of date
–Estimated Execution Plan not valid any more
Proc
Ad hoc
View
---------------------------- SUM
DECLARE @CumulativeTotal MONEY = 0
UPDATE Sales.SalesOrderHeader
SET @CumulativeTotal=CumulativeTotal=@CumulativeTotal+ISNULL(TotalDue, 0)
----------------------------
1)
if (exists(select * from sys.objects where name = N'TRIGGER_HELLO_ON_INSERT'))
BEGIN
PRINT 'Trigger was droped';
DROP TABLE Hello;
END;
2) IF OBJECT_ID(’Product’) IS NOT NULL DROP TABLE Product
?????????????????????????????????????????????
SELECT RANK()
OVER(PARTITION BY Year(OrderDate) ORDER BY OrderDate) as RowNumber,
SalesOrderID, OrderDate, Year(OrderDate) as Year
FROM [Sales].[SalesOrderHeader]
WHERE SalesPersonID = 280
ORDER BY OrderDate
?????????????????????????????????????????????
DECLARE @Temp INT;
SET @Temp = 0;
WHILE @Temp < 3
BEGIN;
PRINT ‘tested condition’ + STR(@Temp);
SET @Temp = @Temp + 1;
END;
SELECT 'True' WHERE 1 < ALL (SELECT a FROM (VALUES (2),(3)) AS ValuesTable(a)); /*All, Some, Any*/
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
--------- SQL -----------------------------------------------------------------------------
- Data Manipulation Language (DML): (Select, Insert, Update, Delete)
- Data Definition Language (DDL)
- Data Control Language (DCL):
--------- SYSTEM --------------------------------------------------------------------------
@@IDENTITY - last identity value generated by SQL
--------- JOINS ---------------------------------------------------------------------------
INNER JOIN - rows that match
LEFT JOIN - rows that match + all left rows that not match OUTER
RIGHT JOIN - rows that match + all right rows that not match OUTER
FULL JOIN - rows that match + all right rows that not match + all left rows that not match OUTER
CROSS JOIN - each left row match each row in right
THETA JOIN
-------------------------------------------------------------------------------------------
--------- TABLE TYPES ---------------------------------------------------------------------
-------------------------------------------------------------------------------------------
CREATE TYPE OrderDetailsType AS Table (
LineNumber INT,
ProductID INT,
IsNew BIT,
IsDirty BIT,
IsDeleted BIT
);
-------------------------------------------------------------------------------------------
--------- FUNCTION and PROCEDURE ----------------------------------------------------------
-------------------------------------------------------------------------------------------
stored procedure can return data:
- select
- raiserror
- external table
- output parameters,
- return (only int)
PROCEDURE vs FUNCTION:
- Procedure can return zero or n values whereas function can return one value which is mandatory.
- Procedures can have input/output parameters for it whereas functions can have only input parameters.
- Procedure allows select as well as DML statement in it whereas function allows only select statement in it.
- Functions can be called from procedure whereas procedures cannot be called from function.
- Exception can be handled by try-catch block in a procedure whereas try-catch block cannot be used in a function.
- We can go for transaction management in procedure whereas we can not go in function.
- Procedures can not be utilized in a select statement whereas function can be embedded in a select statement.
- UDF can be used in the SQL statements anywhere in the WHERE/HAVING/SELECT section where as Stored procedures cannot be.
- UDFs that return tables can be treated as another rowset. This can be used in JOINs with other tables.
- Inline UDFs can be though of as views that take parameters and can be used in JOINs and other Rowset operations.
EXEC dbo.CategoryGet N’Kite’;
DECLARE @nname NVARCHAR(35);
EXEC dbo.GetByName2 @nname output
SELECT @nname
CREATE PROCEDURE dbo.CategoryGet (
@OrderID INT OUTPUT,
@CategoryName NVARCHAR(35) = 'DefafultValue',
@Details as OrderDetailsType READONLY
)
AS
SELECT ProductCategoryName, ProductCategoryDescription
FROM dbo.ProductCategory
WHERE ProductCategoryName = @CategoryName;
call table-valued function:
SELECT * FROM [dbo].[ufnGetContactInformation] (1)
CREATE FUNCTION dbo.AddDigitColumn(@numberAsString nvarchar(50))
RETURNS @result TABLE (
summed int
) as
BEGIN
RETURN;
END;
-------------------------------------------------------------------------------------------
--------- TEMP TABLES ---------------------------------------------------------------------
-------------------------------------------------------------------------------------------
Temp tables(deleted when scope is out): CHOOSE BY SCOPE AND SIZE
1)(tempdb pages in memory) #fooTable - local temporary table (till the end of the session)
- has statistics => better execution plan
2)(tempdb pages in memory) ##fooTable - global temporary table(visible to all users. lives till last user leaves)
- has statistics => better execution plan
3)(tempdb pages in memory) @variables (if has less then 250 rows)
- has no statistcs overhead (bad execution plan for big data)
- the same scope and life as local variable (life is shorte then temp table)
DECLARE #temTable TABLE (oldValue nvarchar(50), newValue nvarchar(50))
DECLARE ##temTable TABLE (oldValue nvarchar(50), newValue nvarchar(50))
DECLARE @temTable TABLE (oldValue nvarchar(50), newValue nvarchar(50))
INSERT into @temTable(oldValue, newValue)
SELECT oldValue, newValue
FROM
(UPDATE Person.Person Set FirstName = 'Aimee+'
OUTPUT Deleted.FirstName as 'oldValue',
Inserted.FirstName as 'newValue'
WHERE FirstName = 'Aimee' AND LastName = 'Hu') Q
SELECT * FROM @temTable
-------------------------------------------------------------------------------------------
--------- DYNAMIC SQL ---------------------------------------------------------------------
-------------------------------------------------------------------------------------------
DYNAMIC SQL:
1) ad-hoc query
EXEC ('SELECT * FROM Person.Person WHERE FirstName = N''Ken'' AND LastName = N''Sánchez''')
2) dynamic sql:
EXEC sp_Executesql /*SQL query plan can be stored because variables are not included in calculated hash*/
N'SELECT * FROM Person.Person WHERE FirstName = @FirstName AND LastName = @LastName',
N'@FirstName NVARCHAR(50), @LastName NVARCHAR(50)',
@FirstName = N'Ken', @LastName = N'Sánchez';
-------------------------------------------------------------------------------------------
--------- MERGE ---------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
MERGE:
MERGE FlightPassengers F /*TargetTable*/
USING CheckIn C /*SourceTable*/
ON C.LastName = F.LastName
AND C.FirstName = F.FirstName
AND C.FlightCode = F.FlightCode
AND C.FlightDate = F.FlightDate
WHEN Matched /* AND .... <extra condition>*/
THEN UPDATE
SET F.Seat = C.Seat
WHEN NOT MATCHED BY TARGET
THEN INSERT (FirstName, LastName, FlightCode, FlightDate, Seat)
VALUES (FirstName, LastName, FlightCode, FlightDate, Seat)
WHEN NOT MATCHED BY SOURCE
THEN DELETE ;
-------------------------------------------------------------------------------------------
--------- ERROR ---------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
BEGIN TRY
END TRY
BEGIN CATCH /*@@error - error status for previous SQL statement*/
RAISERROR (
message or number, severity, state, optional arguments
) WITH LOG;
END CATCH;
-------------------------------------------------------------------------------------------
--------- VIEW ----------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
ALTER VIEW dbo.vCapeHatterasTour -- View can be replaces with table-valued function
WITH ENCRYPTION /*encrypt view code*/
AS
SELECT TourName, BaseCampID
FROM dbo.Tour
WHERE BaseCampID = 2
WITH CHECK OPTION;/*Veiw cannot be modified*/
-------------------------------------------------------------------------------------------
--------- UNION ---------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
UNION - eliminates duplicates
UNION ALL - include duplicates (faster)
-------------------------------------------------------------------------------------------
--------- APPLY ---------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
Correlated subqueries:
1) correlating in the where clause (when "when" is enough)
2) correlating a derived table using apply (when need join) - cross apply and outer apply
CROSS APPLY (Select ID from TableA
SELECT OUTERTABLE.ID AS Bid, A.ID AS Aid
FROM TableB AS OUTERTABLE
where TableA.ID = /*--*/OUTERTABLE.ID/*pass every row from the outer query to the derived table*/) AS A;
/*Functionally, it’s the equivalent to an inner join*/
execute a table-valued function(TVF) or sub-query for rach row returned by outer(left) data source input
CROSS APPLY - only return left-input rows that produce TVF results
OUTER APPLY - returns matched and unmatched oeft-iput rows
SELECT c.BusinessEntityType, c.FirstName, c.LastName, c.JobTitle, c.PersonID
FROM [dbo].[ufnGetContactInformation] (3) AS c;
/*NOT WORKING*/
SELECT c.BusinessEntityType, c.FirstName, c.LastName, c.JobTitle
FROM [Person].[Person] as p
INNER JOIN [dbo].[ufnGetContactInformation] (p.BusinessEntityId) as c
WHERE p.LastName LIKE 'Abo%';
/*SOLVED WITH CROSS APPLY*/
SELECT c.BusinessEntityType, c.FirstName, c.LastName, c.JobTitle
FROM [Person].[Person] as p
CROSS APPLY [dbo].[ufnGetContactInformation] (p.BusinessEntityId) as c
WHERE p.LastName LIKE 'Abo%';
http://www.sql-tutorial.ru/ru/book_cross_apply.html
SELECT P.maker, L.* FROM
Product P
CROSS APPLY
(SELECT * FROM Laptop L WHERE P.model= L.model) L;
------------------------------------------------------------------------------------------
SCALAR FUNCTION:
CREATE FUNCTION FunctionName (InputParameters)
RETURNS DataType
AS
BEGIN;
Code;
RETURN Expression;
END;
EXEC @res = dboMyFunc 1, 2
SELECT dbo.dboMyFunc(1, 2)
INLINE TABLE-VALUED FUNCTION:
CREATE FUNCTION FunctionName (InputParameters)
RETURNS Table
AS
RETURN (Select Statement);
MULTILINE TABLE-VALUED FUNCTION:
CREATE FUNCTION FunctionName (InputParamenters)
RETURNS @TableName TABLE (Columns)
AS
BEGIN;
Code to populate table variable
RETURN;
END;
-------------------------------------------------------------------------------------------
--------- CURSOR --------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
CURSOR TYPES: static - copyes all to tempDb(fastest)
keyset - copyies minium needed to tempDb
dynamic - iterated original data
fast_forward - "high-performance" read-only forward-only dynamic cursor
CURSOR PARAMETERS: forward_only - forward only dynamic cursor
scroll - can go to any of: first, last, prior, next, raltive, or absolute
read_only
scroll_locks - all updates or delete made through the cursor are guaranted to success. (rows are locked)
optimistic - does not lock rows. If it was modified outside the ouside will win.
USE CURSOR WHEN:
- iterating over a stored procedure
- iterating over DDL code
- cumulative Totals/Running Sums
- time-sensetive data
@@cursor_rows - returns the number of rows in the cursor (if cursor populated asynchronosusly then it returns negative number)
@@fetch_status - status after the last FETCH command
0 successfully retrived row
-1 The last FETCH failed by reaching the end of the result set, trying to fetch prior to a row before the beginning of the result set, or the fetch simply failed
-2: The last row fetched was not available; the row has been deleted.
----- UPDATE --------------------------------------------------------------------------------
UPDATE Detail
SET AdjAmount = @SprocResult
WHERE CURRENT OF cDetail;
----- LOCAL and GLOBAL ----------------------------------------------------------------------
ALTER DATABASE Family SET CURSOR_DEFAULT LOCAL/*default to database level*/
SELECT DATABASEPROPERTYEX(’Family’, ‘IsLocalCursorsDefault’);
----- SAMPLE --------------------------------------------------------------------------------
DECLARE @LocationID SMALLINT,
@LocationName VARCHAR(50);
DECLARE cLocation CURSOR STATIC /*STATIC | KEYSET | DYNAMIC | FAST_FORWARD*/ LOCAL /*GLOBAL*/
FOR SELECT/*UPDATE*/ LocationID, Name
FROM Production.Location
ORDER BY Name;
OPEN cLocation;
FETCH cLocation
INTO @LocationID,
@LocationName;
WHILE @@Fetch_Status <> -1 -- = 0
BEGIN;
IF @@Fetch_Status = 0
BEGIN;
PRINT CAST(@LocationName as CHAR(10))
END;
IF @@Fetch_Status = -2 PRINT 'Hit Deleted Row (possible only with keyset cursor)';
FETCH cLocation
INTO @LocationID,
@LocationName;
END;
CLOSE cLocation;
DEALLOCATE cLocation;
-------------------------------------------------------------------------------------------
OLAP functions: (generate subtotals and grand totals as separate rows, and supply a null in the
GROUP BY column to indicate the grand total)
1) CUBE, - It adds subtotals for every possible grouping in a multidimensional manner
2) ROLLUP - generate an additional total row.
3) PIVOT(Crosstab Queries) - pivots the second GROUP BY column
(or dimension) values counterclockwise 90 degrees and turns it into the crosstab columns
A special GROUPING() function is true when the row is a subtotal or grand total row for the group.
1) ...
GROUP BY Year(SalesDate), DatePart(q,SalesDate);
2) ...
GROUP BY GROUPING SETS (Category, Region);
[[... GROUP BY Region UNION ... GROUP BY Category;]]
-------------------------------------------------------------------------------------------
--------- GROUPING SETS -------------------------------------------------------------------
-------------------------------------------------------------------------------------------
GROUPING SETS as executing several GROUP BY queries (one for each grouping set) and then combining, or
unioning, the results
SELECT Category,
Region,
COUNT(*) AS Count,
SUM(Amount) AS [Sum],
FROM RawData
GROUP BY GROUPING SETS (Category, Region);
SELECT Category, Y, Q, Total,
RANK() OVER (PARTITION BY Y, Q ORDER BY Total DESC) AS rn
FROM AllQuery)
-------------------------------------------------------------------------------------------
--------- ROLLUP --------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
SELECT
CASE GROUPING(Category)
WHEN 0 THEN Category
WHEN 1 THEN ‘All Categories’
END AS Category,
CASE GROUPING(Region)
WHEN 0 THEN Region
WHEN 1 THEN ‘All Regions’
END AS Region,
SUM(Amount) AS Amount
FROM RawData
GROUP BY ROLLUP(Category, Region) /*instructs Server to generate an additional total rows (one for Category, one for Region)*/
--ROLLUP can be used to generate a subtotal rows and a grand total row for aggregate rows
-------------------------------------------------------------------------------------------
--------- CUBE ----------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
CUBE = ROLLUP + rows with 'All Regions' and categories
SELECT
CASE GROUPING(Category)
WHEN 0 THEN Category
WHEN 1 THEN ‘All Categories’
END AS Category,
CASE GROUPING(Region)
WHEN 0 THEN Region
WHEN 1 THEN ‘All Regions’
END AS Region,
COUNT(*) AS Count
FROM RawData R
GROUP BY CUBE(Category, Region) /*It adds subtotals for every possible grouping in a multidimensional manner*/
ORDER BY Coalesce(R.Category, ‘ZZZZ’), Coalesce(R.Region, ‘ZZZZ’)
-------------------------------------------------------------------------------------------
--------- PIVOT ---------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
Add pivoted columns to every row. It is like table-valued function.
SELECT Category, MidWest, NorthEast, South, West
FROM (SELECT Category, Region, Amount FROM RawData) sq -- <-- subselect for selecting columns that should be submitted to the PIVOT
PIVOT
(SUM(Amount)
FOR Region IN (MidWest, NorthEast, South, West)
) AS pt
SELECT Name, Multi, White, Grey, Silver
FROM [Production].[Product]
PIVOT (SUM(StandardCost)
FOR COLOR IN (Multi, White, Grey, Silver)
) as pt
--------------
SELECT *
FROM PTable
UNPIVOT
(Measure
FOR Region IN
(South, NorthEast, MidWest, West)
) as sq
SELECT CASE GROUPING(Category)
WHEN 0 THEN Category
WHEN 1 THEN ‘All Categories’
END AS Category,
SUM(CASE WHEN Region = ‘MidWest’ THEN Amount ELSE 0 END) AS MidWest,
SUM(CASE WHEN Region = ‘NorthEast’ THEN Amount ELSE 0 END) AS NorthEast,
SUM(CASE WHEN Region = ‘South’ THEN Amount ELSE 0 END) AS South,
SUM(CASE WHEN Region = ‘West’ THEN Amount ELSE 0 END) AS West,
SUM(Amount) AS Total
FROM RawData
GROUP BY RollUp (Category)
ORDER BY Coalesce(Category, ‘ZZZZ’)
-------------------------------------------------------------------------------------------
--------- WINDOWING AND RANKING -----------------------------------------------------------
-------------------------------------------------------------------------------------------
WINDOWING AND RANKING(using the over() clause creates a new window on the data):
- ranking functions: row_number, rank, dense_rank, ntile
SELECT ROW_NUMBER() OVER(ORDER BY OrderDate) as RowNumber,
SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader
WHERE SalesPersonID = 280
ORDER BY RowNumber;
OVER() clause generates the sort order for the ranking functions
Over executes after where
Group By returns one row from grouping set when Partition by does not change result count
1) order by xxx
2) partition to partitions or just one partition
3) add extra info to every row (for exapmle to what partition belongs)
Ranking functions:
ROW_NUMBER() - number in partition
RANK() - rank where (1, 2, 2, 4)
DENSE_RANK() - rank where all ranks are (1, 2, 2, 3)
ntile(5) - partition to 5 equally sized groups
Max, Min, ...
SELECT ROW_NUMBER()
OVER(Partition By
Year(OrderDate),
Month(OrderDate)
ORDER BY OrderDate) as RowNumber,
SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader
WHERE SalesPersonID = 280
ORDER BY OrderDate;
/*OVER clause defines a "window" within a specific query result set*/
SELECT p.ProductID,
p.Name,
ROW_NUMBER() OVER (ORDER BY p.ProductID) as RowNum
FROM [Production].[Product] as p
ORDER BY p.ProductID
SELECT p.ProductID,p.Color,
p.Name,
ROW_NUMBER() OVER (PARTITION BY p.Color ORDER BY p.Name) as RowNum
FROM [Production].[Product] as p
WHERE p.Color IS NOT NULL
ORDER BY p.Color, p.Name
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
--------- HIERARCHIES ---------------------------------------------------------------------
-------------------------------------------------------------------------------------------
Traversing Hierarhies:
1)Adjacency list(pattern or self-join pattern)
1.1) for each level needs join
1.2) Recursive CTE
+ reparenting is trivial
+ it is easy to manually decode and uderstand
- requires checking for cyclic errors
- good performance, but slower then hierarchyID
2) Materialized path
+ more stable because every node has full path
+ the only pattern that can retrieve subtree with a single index seek
- key size
- needs trigger cheks for validation
3) HierarchyID
+ fast
- hard to read binary data
- can be damaged in case of removing parent node(it does not save full path)
4) user defined function and procedures
5) xml
------ CTE -------------------------------------------------------------------------------
WITH OrgPath (BusinessEntityID, ManagerID, lv)
AS (
-- Anchor
SELECT BusinessEntityID, ManagerID, 1
FROM HumanResources.Employee
WHERE ManagerID IS NULL -- should only be EmployeeID 1
-- Recursive Call
UNION ALL
SELECT E.BusinessEntityID, E.ManagerID, lv + 1
FROM HumanResources.Employee AS E
JOIN OrgPath
ON E.ManagerID = OrgPath.BusinessEntityID
)
SELECT BusinessEntityID, ManagerID, lv
FROM OrgPath
ORDER BY Lv, BusinessEntityID
OPTION (MAXRECURSION 20);
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
--------- TRANSACTIONS --------------------------------------------------------------------
-------------------------------------------------------------------------------------------
ACID - atomicity(атомарность), consistency(непротиворечивость), isolation(изолированность), durability(устойчивость)
Lock mode:
- shared (S) - readonly operations (select)
- update (U) - on updated resources
- exclusive (X) - on data-modification opearaitons (inser, update, delete)
- intend - for lock hierarchy
- schema - when operation depends on schema
- bulk update (BU)
--------- DEADLOCK ------------------------------------------------------------------------
DEADLOCK (http://technet.microsoft.com/en-us/library/ms178104(v=sql.105).aspx)
Resources that can cause deadlock: locks, worker thread, memory, parraller query-related resources, multiple active result sets
--------- TRANSACTION ISOLATION LEVELS ---------------------------------------------------- http://ru.wikipedia.org/wiki/%D0%A3%D1%80%D0%BE%D0%B2%D0%B5%D0%BD%D1%8C_%D0%B8%D0%B7%D0%BE%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8_%D1%82%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D0%B9
Non-repeatable reads - reading second time in transaction gives modified data
phantom read - reading second time in transaction gives differen rows count
|Phantoms| Non-repeatable reads | Dirty reads|Lost update
1) read uncommitted(dirty read) - never use | - | - | - | +
2) read committed (DEFAULT) | - | - | + | +
3) repeatable read - other transactions cannot change what we read | - | + | + | +
4) serializable - fully isolated, like sequential requests | + | + | + | +
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ/*READ UNCOMMITTED, READ COMMITTED, SNAPSHOT, SERIALIZABLE*/;
--------- TRANSACTION FLOW ----------------------------------------------------------------
1. IDENTITY INSERT check
2. Nullability constraint
3. Data-type check
4. INSTEAD OF trigger execution. If an INSTEAD OF trigger exists, then execution of the DML
stops here. INSTEAD OF triggers are not recursive. Therefore, if the INSERT trigger executes
another DML command, then the INSTEAD OF trigger will be ignored the second time around
(recursive triggers are covered later in this chapter).
5. Primary-key constraint
6. Check constraints
7. Foreign-key constraint
8. DML execution and update to the transaction log
9. AFTER trigger execution
10. Commit transaction (for more details on commits, see Chapter 66, ‘‘Managing Transactions, Locking, and Blocking’’)
-------------------------------------------------------------------------------------------
--------- TRIGGERS ------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
After trigger can not be applyed to views.
CREATE TRIGGER Schema.TriggerName ON Schema.TableName
AFTER | INSTEAD OF [Insert, Update, (and or) Delete]
AS
Trigger Code;
IF (UPDATE(Name)) BEGIN PRINT('Name was modified'); END;
ALTER DATABASE DatabaseName SET RECURSIVE_TRIGGERS ON | OFF ; /*for calling the same trigger from itself*/
EXEC sp_configure ‘Nested Triggers’, 0;
RECONFIGURE;
If Trigger_NestLevel() > 1
Return;
--------- DDL TRIGGER ------------------------------------------------------------------------
CREATE TRIGGER SchemaAudit
ON DATABASE /*ALL SERVER*/
[WITH ENCRYPTION]
FOR DDL_Database_Level /*DDL_DATABASE_LEVEL_EVENTS, Create_Table*/
AS
code
/*
DECLARE @EventData XML = EventData()
SELECT @EventData.value('data(/EVENT_INSTANCE/SchemaName)[1]','VARCHAR(50)') as 'Schema',
@EventData.value('data(/EVENT_INSTANCE/ObjectName)[1]', 'VARCHAR(50)') as 'Object',
@EventData.value('data(/EVENT_INSTANCE/EventType)[1]', 'VARCHAR(50)') as 'EventType'
*/
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
--------- XML -----------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
XML variable or column:
- typed (bound to XML schema collection)
- untyped
Read XML:
- OPENXML()
- XQuery
XML(XQuery):
-- Declare an XML variable
DECLARE @x XML
-- Declare a TYPED XML Variable
DECLARE @x XML(CustomerSchema)
-- Declare a TYPED XML DOCUMENT Variable
DECLARE @x XML(DOCUMENT CustomerSchema)
-- Declare a TYPED XML CONTENT variable
DECLARE @x XML(CONTENT CustomerSchema)
SELECT
x.value(’@ItemNumber’,’CHAR(4)’) AS ItemNumber,
x.value(’@Quantity’,’INT’) AS Quantity,
x.value(’@Price’,’MONEY’) AS Price
FROM (
SELECT CAST(bulkcolumn AS XML) AS data
FROM OPENROWSET(BULK ‘C:\temp\items.xml’, SINGLE_BLOB)
AS x
) a
CROSS APPLY data.nodes(’/Items/Item’) i(x)
DECLARE @x XML
SELECt @x = ‘<Order OrderID="1" OrderNumber="SO101" />’
SELECT
@x.value(’(Order/@OrderID)[1]’,’INT’) AS OrderID,
@x.value(’(Order/@OrderNumber)[1]’,’CHAR(5)’) AS OrderNumber
CREATE TABLE OrderXML (OrderID INT, ItemData XML)
INSERT INTO OrderXML (OrderID, ItemData) SELECT 2, '<Order OrderID="2">
<Item ItemNumber="D001" Quantity="1" Price="900"/>
</Order>'
XML methods:
- value()
- exists()
- query()
- modify()
- nodes()
xml variable can be initialized from:
- xml string,
- xml
- varchar, nvarchar,
- varbinary
- FOR XML
- XML file
DECLARE @xml XML
SELECT @xml = CAST(bulkcolumn AS XML)
FROM OPENROWSET(BULK ‘C:\temp\items.xml’, SINGLE_BLOB) AS x
-- Declare an XML variable
DECLARE @x XML
-- Declare a TYPED XML Variable
DECLARE @x XML(CustomerSchema)
-- Declare a TYPED XML DOCUMENT Variable
DECLARE @x XML(DOCUMENT CustomerSchema)
-- Declare a TYPED XML CONTENT variable
DECLARE @x XML(CONTENT CustomerSchema)
-----------------------------------------------------
DECLARE @t TABLE (OrderID INT,OrderData XML )
INSERT INTO @t(OrderID, OrderData)
SELECT 1, '<CustomerNumber>1001</CustomerNumber>
<Items>
<Item ItemNumber="1001" Quantity="1" Price="950"/>
<Item ItemNumber="1002" Quantity="1" Price="650" />
</Items>'
SELECT OrderID,
OrderData.value('CustomerNumber[1]','CHAR(4)') AS CustomerNumber
FROM @t
-----------------------------------------------------
DECLARE @t TABLE (OrderID INT,OrderData XML )
INSERT INTO @t(OrderID, OrderData)
SELECT 1, '<CustomerNumber>1001</CustomerNumber>
<Items>
<Item ItemNumber="1001" Quantity="1" Price="950"/>
<Item ItemNumber="1002" Quantity="1" Price="650" />
</Items>'
SELECT OrderID,
o.value('@ItemNumber','CHAR(4)') AS ItemNumber,
o.value('@Quantity','INT') AS Quantity,
o.value('@Price','MONEY') AS Price
FROM @t
CROSS APPLY OrderData.nodes('/Items/Item') x(o)
--------- USE VARIABLE IN XQuery (sql:variable) ------------------------------------------
DECLARE @ItemNumber CHAR(4)
SELECT @ItemNumber = ‘D001’
SELECT x.value(’@ItemNumber’,’CHAR(4)’) AS ItemNumber,
x.value(’@Quantity’,’INT’) AS Quantity,
x.value(’@Price’,’MONEY’) AS Price
FROM OrderXML
CROSS APPLY ItemData.nodes(’/Order/Item[@ItemNumber=sql:variable("@ItemNumber")]’) o(x)
---------- PRODUCE XML STRING OR XML FROM TABLE -------------------------------------------------
generating XML documents:
- FOR XML PATH
- FOR XML EXPLICIT
- FOR XML AUTO
- FOR XML RAW
FOR XML is a row set aggregation function that returns a one-row, one-column result set containing an
NVARCHAR(MAX) value. The TYPE directive can be used along with FOR XML to produce XML data
type output instead of NVARCHAR(MAX).
SELECT OrderNumber, CustomerID
FROM OrderHeader
FOR XML AUTO
/*
<OrderHeader OrderNumber="SO101" CustomerID="1" />
<OrderHeader OrderNumber="SO102" CustomerID="1" />
*/
SELECT OrderNumber, CustomerID
FROM OrderHeader
FOR XML AUTO, ROOT('SalesOrder')
/*
<SalesOrder>
<OrderHeader OrderNumber="SO101" CustomerID="1" />
<OrderHeader OrderNumber="SO102" CustomerID="1" />
</SalesOrder>
*/
----------- GENERATE SCHEMA ---------------------------------------------------------------
1) from table
SELECT OrderNumber, CustomerID
FROM OrderHeader [Order]
FOR XML AUTO, XMLSCHEMA --FOR XML AUTO, XMLSCHEMA(’urn:some-namespace’)
2) from string
CREATE XML SCHEMA COLLECTION CustomerSchema AS '
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Customer">
...
</xs:element>
</xs:schema>'
GO
----------- NAMESPACE ---------------------------------------------------------------------
;WITH XMLNAMESPACES(
DEFAULT ‘http://www.sqlserverbible.com/order’,
‘http://www.sqlserverbible.com/customer’ AS cust -- cust can be used then in XQuery
)
WITH XMLNAMESPACES(
'http://www.sqlserverbible.com/orders' AS ord
)
SELECT CustomerID AS '@CustomerID',
OrderNumber AS 'data()'
FROM OrderHeader
FOR XML PATH('Order'),ROOT('Orders')
--------------------------------------------------------------------------------------------
----------- XQuery -------------------------------------------------------------------------
--------------------------------------------------------------------------------------------
SELECT
ItemData.query('/Order/Item')
FROM OrderXML
-----------------------------------------
FLWOR operation (FOR LET WHERE ORDER BY and RETURN) <----- the most powerfull XQuery operation
DECLARE @x XML
SELECT @x = '<Items>
<ItemNumber>1003</ItemNumber>
<ItemNumber>1004</ItemNumber>
</Items>'
SELECT @x.query('for $item in Items/ItemNumber
where $item[. < "2000"]
order by $item
return $item')
SELECT @x.query('for $item in Item
return
<ItemNumber>
{data($item/@ItemNumber)}
</ItemNumber> ')
-----------------------------------------
using System;
namespace ConsoleApplication13
{
interface ICovariant<out T> //can be cast to base
{
//void From(T input);
T To();
}
interface IContravariant<in T> // can be case to derived
{
void From(T input);
//T To();
}
public class Something<T> : ICovariant<T>, IContravariant<T>
{
public void From(T input) { }
public T To() { return default(T);}
}
class Program
{
static void Main(string[] args)
{
ICovariant<object> stringsAsObjects = new Something<string>();
IContravariant<string> objectsAsStrings = new Something<object>();
Console.ReadKey();
}
}
}
idempotent = can be applied multiple times without changing the result
--------------------------------------------
Create => HTTP PUT //operation is idempotent
Retrieve => HTTP GET
Update => HTTP POST //operation is not idempotent
Delete => HTTP DELETE
HEAD
--------------------------------------------
POST should be used to create a resource, and PUT should be used to modify one
PUT should be used to create a resource, and POST should be used to modify one
--------------------------------------------
POST - is good for creating new objects under a collection (and create does not need to be idempotent)
PUT - is good for updating existing objects (and update needs to be idempotent)
POST - can also be used for non-idempotent updates to existing objects (especially, changing part of an
object without specifying the whole thing -- if you think about it, creating a new member of a
collection is actually a special case of this kind of update, from the collection's perspective)
PUT - can also be used for create if and only if you allow the client to name the resource. But since
REST clients aren't supposed to make assumptions about URL structure, this is less in the
intended spirit of things.
----------------------------------------------------------------------
System.ServiceModel.dll
[DataContract] //abstract class System.ServiceModel.Channnels.Message: IDisposable{...}
public class FooClass {
[DataMember]
public string Id;
}
[ServiceContract]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single<<PerCall, PerSession>>,
ConcurrencyMode=ConcurrencyMode.Multiple<<Single,Reentrant>>)]
public interface IXXXService {
[OparationContract(IsOneWay = true/*will not send response*/)]
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
void DoSoem(FooClass param);
}
public class XXXService : IXXXService { ... }
----------------------------------------------------------------------
behaviors: service, client
ENDPOINT : adress("http://s/xxxservice"),//where to send
binding("webHttpBinding"), //how to send
contract("IXXXService") //what messages must send
----------------------------------------------------------------------
WebHttpBinding - interoperable RESTful communication via HTTP
BasicHttpBinding - Iteroperable SOAP communication via HTTP, offering
only the "basic" protocols conforming
WS-I Basic Profile
WSHttpBinding - interoparable SOAP communication via HTTP,
offering the full range of SOAP + WS-* protocols
NetTcpBinding - Cross-machine WCF communication via TCP
NetPeerTcpBinding - Cross-machine WCF communication via P2P
NetNamedPipesBinding - Same-machine WCF communication via IPC
NetMsmqBinding - Disconnected/asynchronous WCF communication via MSMQ
CustomBinding
1) NetXXX binding designed for .NET-to-.NET communication
2) WS-* protocols
3) Mex(WS-MetadataExchange) metadata(WSDL definition) - mex endpoint (IMetadataExchange)
HttpGetEnabled = true//share metadata through http get request
mexTcpBinding
----------------------------------------------------------------------
Hosting:
1) selfhosting
var host = new ServiceHost(typeof(XXXService)); host.Open() host.Close(); host.Abort();
host.AddServiceEndpoint(typeof(XXXXService), new BasicHttpBnding(), "http://.....");
2) managed hosting(IIS/ASP.NET applications)
----------------------------------------------------------------------
Exceptions:
WCF automatically translates exceptions into SOAP falts(no info)
Include exception details:
- [ServiceBehavior(IncludeExceptionDetailInFaults = true)] on class
- <behaior name = "Default">
<serviceDebug includeExceptionDetailsInFaults = "true />
</behavior>
--------------------
FaultException class represents an explicit SOAP fault(throw in a service operation to return a soap fault)
Client can handle this exception.
----------------------------------------------------------------------
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Microsoft.Samples.GettingStarted.CalculatorService"
behaviorConfiguration="CalculatorServiceBehavior">
<endpoint address="" binding="basicHttpBinding" contract="ICalculator"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
</configuration>
----------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment