Last active
February 13, 2020 07:28
-
-
Save iarovyi/a47653f2c5329552a689 to your computer and use it in GitHub Desktop.
NOTES
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
// --------------------------------------------------------- | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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; | |
} | |
} | |
} | |
---------------------------------------------------------------- | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
---------------------------------------------------------------------------------------------- | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
------------------------------------------------------------------------------ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
---------------------------------------------------------------------------------- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
-------------------------------------------------------- | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
----------------------------------------------------------------------------------- | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
& 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. | |
------------------------------------------------------------------------------------------------ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
+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"); | |
} | |
--------------------------------------------------- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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>) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | |
------------------------------------------------ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} | |
} | |
-------------------------------------------------------------------------- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}) | |
_______________________________________________________________________ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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). | |
---------------------------------------------------------------------------------- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
---------------------------------------------------------------------------- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$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; | |
} | |
} | |
---------------------------------------------- | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------------------------------------------------------------- | |
--------- 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; | |
------------------------------------------------------------------------------------------- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
------------------------------------------------------------------------------------------- | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------------------------------------------------------------- | |
--------- 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); | |
------------------------------------------------------------------------------------------- | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------------------------------------------------------------- | |
--------- 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' | |
*/ | |
------------------------------------------------------------------------------------------- | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------------------------------------------------------------- | |
--------- 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> ') | |
----------------------------------------- | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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