DebuggerStepThroughAttribute
class Program { public static void Main(string[] args) { DebuggerStepThroughMethod1(); } [DebuggerStepThrough] public static void DebuggerStepThroughMethod1() { Console.WriteLine( "Method 1" ); DebuggerStepThroughMethod2(); } [DebuggerStepThrough] public static void DebuggerStepThroughMethod2() { Console.WriteLine( "Method 2" ); } }
ConditionalAttribute
class Program { public static void Main(string[] args) { DebugMode(); } [Conditional("DEBUG")] public static void DebugMode() { Console.WriteLine( "Debug mode" ); } }
#define ReleaseMode
Flags Enum Attribute
[System.Flags] public enum Permission { View = 1, Insert = 2, Update = 4, Delete = 8 }
public static void Main( string[] args ) { var permission = ( Permission.View | Permission.Insert ).ToString(); Console.WriteLine( permission ); // Displays ‘View, Insert’ var userPermission = Permission.View | Permission.Insert | Permission.Update | Permission.Delete; // To retrieve the value from property you can do this if ( ( userPermission & Permission.Delete ) == Permission.Delete ) { Console.WriteLine( "کاربر دارای مجوز دسترسی به عملیات حذف میباشد" ); } // In .NET 4 and later Console.WriteLine( userPermission.HasFlag( Permission.Delete ) ? "کاربر دارای مجوز دسترسی به عملیات حذف میباشد" : "کاربر مجوز دسترسی به عملیات حذف را ندارد"); }
نکته: در صورتیکه مقداری را برای enum تعریف کرده باشید، نمیتوانید آن را با مقدار 0 مشخص کنید (در زمانی که ویژگی flags را بر روی enum اضافه کرده باشید)، چرا که با استفاده از عملیات بیتی AND نمیتوانید دارا بودن آن مقدار را تست کنید و همیشه نتیجه صفر خواهد بود.
Dynamically Compile and Execute C# Code
CodeDOM
public static void Main( string[] args ) { var sourceCode = @"class DotNetTips { public void Print() { System.Console.WriteLine("".Net Tips""); } }"; var compiledAssembly = CompileSourceCodeDom( sourceCode ); ExecuteFromAssembly( compiledAssembly ); } static Assembly CompileSourceCodeDom( string sourceCode ) { CodeDomProvider csharpCodeProvider = new CSharpCodeProvider(); var cp = new CompilerParameters { GenerateExecutable = false }; cp.ReferencedAssemblies.Add( "System.dll" ); var cr = csharpCodeProvider.CompileAssemblyFromSource( cp, sourceCode ); return cr.CompiledAssembly; }
Roslyn
سکوی کامپایلر دات نت " Roslyn "، کامپایلرهای متن باز #C و VB.NET را به همراه APIهای تجزیه و تحلیل کد ارائه کرده است که با استفاده از این APIها میتوان ابزارهای آنالیز کد جهت استفاده در ویژوال استودیو را ایجاد کرد.
برای استفاده از Roslyn باید این کتابخانه را نصب کنید
Install-Package Microsoft.CodeAnalysis
حال مثال قبل را با استفاده از Roslyn بازنویسی میکنیم:
public static void Main(string[] args) { var sourceCode = @"class DotNetTips { public void Print() { System.Console.WriteLine("".Net Tips""); } }"; var compiledAssembly = CompileSourceRoslyn( sourceCode ); ExecuteFromAssembly( compiledAssembly ); } private static Assembly CompileSourceRoslyn(string sourceCode) { using ( var memoryStream = new MemoryStream() ) { var assemblyFileName = string.Concat( Guid.NewGuid().ToString(), ".dll" ); var compilation = CSharpCompilation.Create( assemblyFileName, new[] { CSharpSyntaxTree.ParseText( sourceCode ) }, new[] { MetadataReference.CreateFromFile( typeof( object ).Assembly.Location ) }, new CSharpCompilationOptions( OutputKind.DynamicallyLinkedLibrary ) ); compilation.Emit( memoryStream ); var assembly = Assembly.Load( memoryStream.GetBuffer() ); return assembly; } }
و جهت فراخوانی اسمبلی ساخته شده به هر دو روش بالا، از کد زیر استفاده میکنیم.
static void ExecuteFromAssembly( Assembly assembly ) { var helloKittyPrinterType = assembly.GetType( "DotNetTips" ); var printMethod = helloKittyPrinterType.GetMethod( "Print" ); var kitty = assembly.CreateInstance( "DotNetTips" ); printMethod.Invoke( kitty, BindingFlags.InvokeMethod, null, null, CultureInfo.CurrentCulture ); }
Nullable<T>.GetValueOrDefault Method
float? yourSingle = -1.0f; Console.WriteLine( yourSingle.GetValueOrDefault() ); yourSingle = null; Console.WriteLine( yourSingle.GetValueOrDefault() ); // assign different default value Console.WriteLine( yourSingle.GetValueOrDefault( -2.4f ) ); // returns the same result as the above statement Console.WriteLine( yourSingle ?? -2.4f );
در صورتیکه مقداری را به عنوان پیش فرض، به پارامتر این متد ارسال نکنید، مقدار پیش فرض آن از نوع استفاده شده بدست میآید.
شما میتوانید برای دیکشنری نیز یک متد Get امن ایجاد کنید (در صورت عدم وجود کلید، بجای پرتاب استثناء، مقدار پیش فرض بازگشت داده شود).
public static class DictionaryExtensions { public static TValue GetValueOrDefault< TKey, TValue >( this Dictionary< TKey, TValue > dic, TKey key ) { TValue result; return dic.TryGetValue( key, out result ) ? result : default(TValue); } }
و روش استفاده
var names = new Dictionary< int, string > { { 0, "Vahid" } }; Console.WriteLine( names.GetValueOrDefault( 1 ) );
ZipFile in .NET
var startPath = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.Desktop ), "Start" ); var resultPath = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.Desktop ), "Result" ); var extractPath = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.Desktop ), "Extract" ); Directory.CreateDirectory( startPath ); Directory.CreateDirectory( resultPath ); Directory.CreateDirectory( extractPath ); var zipPath = Path.Combine( resultPath, Guid.NewGuid() + ".zip" ); ZipFile.CreateFromDirectory( startPath, zipPath ); ZipFile.ExtractToDirectory( zipPath, extractPath );
C# Preprocessor Directives
#if DEBUG #warning DEBUG is defined #endif
#if DEBUG #error DEBUG is defined #endif
در مثال زیر، در صورتیکه در خط اول break point قرار دهید و با کلید F10 برنامه را اجرا کنید، مشاهده میکنید که دیباگر، خطی را که بعد از دستور line hidden# نوشته شده است، در نظر نمیگیرد (برای دیباگ) اما اجرا میشود و دیباگر بر روی دستور بعد از line default# قرار میگیرد.
Console.WriteLine("Normal line #1."); // Set break point here. #line hidden Console.WriteLine("Hidden line."); #line default Console.WriteLine("Normal line #2.");
Stackalloc
static unsafe void Fibonacci() { const int arraySize = 20; int* fib = stackalloc int[arraySize]; var p = fib; *p++ = *p++ = 1; for ( var i = 2; i < arraySize; ++i, ++p ) { *p = p[-1] + p[-2]; } for ( var i = 0; i < arraySize; ++i ) { System.Console.WriteLine( fib[i] ); } }
Parallel.For & Parallel.ForEach
var nums = Enumerable.Range( 0, 1000000 ).ToArray(); long total = 0; // Use type parameter to make subtotal a long, not an int Parallel.For< long >( 0, nums.Length, () => 0, ( j, loop, subtotal ) => { subtotal += nums[j]; return subtotal; }, x => Interlocked.Add( ref total, x ) ); Console.WriteLine( "The total is {0:N0}", total );
var nums = Enumerable.Range( 0, 1000000 ).ToArray(); long total = 0; Parallel.ForEach< int, long >( nums, // source collection () => 0, // method to initialize the local variable ( j, loop, subtotal ) => // method invoked by the loop on each iteration { subtotal += j; //modify local variable return subtotal; // value to be passed to next iteration }, // Method to be executed when each partition has completed. // finalResult is the final value of subtotal for a particular partition. finalResult => Interlocked.Add( ref total, finalResult ) ); Console.WriteLine( "The total from Parallel.ForEach is {0:N0}", total );
IsInfinity
Console.WriteLine("IsInfinity(3.0 / 0) == {0}.", double.IsInfinity(3.0 / 0) ? "true" : "false");
dynamic Type
با استفاده از نوع dynamic می توان عملیات چک کردن نوع در زمان کامپایل را پشت سر گذاشت و در عوض این عملیات را به زمان اجرا، موکول داد.
نکته: نوع dynamic همانند نوع object در بسیاری از شرایط، یکسان رفتار میکند. اگرچه عملیاتهایی که شامل عبارتهایی از نوع dynamic هستند، یا نوع آن توسط کامپایلر بررسی میشوند و یا پذیرفته نمیشوند. کامپایلر اطلاعات مربوط به یک پردازش (روند) را یکجا بسته بندی میکند و این اطلاعات را بعداً در زمان اجرا ارزیابی میکند. به عنوان بخشی از این پردازش، متغیرهایی از نوع dynamic به متغیرهایی از نوع object کامپایل میشوند. بنابراین نوع dynamic فقط در زمان کامپایل وجود دارند (نه در زمان اجرا).
var i = 20; dynamic dynamicVariable = i; Console.WriteLine( dynamicVariable ); var stringVariable = "Example string."; dynamicVariable = stringVariable; Console.WriteLine( dynamicVariable ); var dateTimeVariable = DateTime.Today; dynamicVariable = dateTimeVariable; Console.WriteLine( dynamicVariable ); // The expression returns true unless dynamicVariable has the value null. if ( dynamicVariable is dynamic ) Console.WriteLine( "dynamicVariable variable is dynamic" ); // dynamic and the as operator. dynamicVariable = i as dynamic; // throw RuntimeBinderException if the associated object doesn't have the specified method. // The code is still compiling successfully. Console.WriteLine( dynamicVariable.ToNow1 );
همانطور که در مثال بالا مشاهده میکنید، شما میتوانید متغیرهایی از نوعهای مختلف را به یک شی از نوع dynamic اختصاص دهید. همچنین میتوانید برای بررسی یک متغیر که از نوع dynamic است یا خیر، از عملگر is استفاده کنید. اگر یک خصوصیت را که وجود ندارد، درخواست کنید (خط آخر مثال بالا)، خطای RuntimeBinderException پرتاب میشود.
ExpandoObject
dynamic sampleObject = new ExpandoObject(); sampleObject.FirstName = "Vahid"; sampleObject.LastName = "Mohammad Taheri"; sampleObject.Age = "28"; sampleObject.TestRemoveProperty = DateTime.Now; sampleObject.AsString = new Action( () => Console.WriteLine( "{0} {1} is {2} years old.", sampleObject.FirstName, sampleObject.LastName, sampleObject.Age ) ); sampleObject.AsString();
( (IDictionary< String, Object >)sampleObject ).Remove( "TestRemoveProperty" );
__arglist __reftype __makeref __refvalue کلمات کلیدی
var i = 28; TypedReference tr = __makeref( i ); Type t = __reftype( tr ); Console.WriteLine( t ); int rv = __refvalue( tr, int ); Console.WriteLine( rv ); ArglistTest.DisplayNumbers( __arglist( 1, 2, 3, 5, 6 ) );
public static class ArglistTest { public static void DisplayNumbers( __arglist ) { var ai = new ArgIterator( __arglist ); while ( ai.GetRemainingCount() > 0 ) { var tr = ai.GetNextArg(); Console.WriteLine( TypedReference.ToObject( tr ) ); } } }
Environment.NewLine
Console.WriteLine( "NewLine: {0}first line{0}second line{0}third line", Environment.NewLine );
ExceptionDispatchInfo
ExceptionDispatchInfo possibleException = null; try { int.Parse( "a" ); } catch ( FormatException ex ) { possibleException = ExceptionDispatchInfo.Capture( ex ); } possibleException?.Throw();
Debug.Assert & Debug.WriteIf & Debug.Indent
Debug.Assert(1 == 0, "عدد 1 برابر با 0 نیست");
Debug.WriteIf( 1 == 1, "display message in output window :D" );
Debug.WriteLine("تست تورفتگی"); Debug.Indent(); Debug.WriteLine("یک واحد افزایش داده شد"); Debug.Unindent(); Debug.WriteLine("یک واحد کاهش داده شد"); Debug.WriteLine("پایان تست");
Curry and Partial methods
public static class CurryMethodExtensions { public static Func< A, Func< B, Func< C, R > > > Curry< A, B, C, R >( this Func< A, B, C, R > f ) { return a => b => c => f( a, b, c ); } }
Func< int, int, int, int > addNumbers = ( x, y, z ) => x + y + z; var f1 = addNumbers.Curry(); Func< int, Func< int, int > > f2 = f1( 3 ); Func< int, int > f3 = f2( 4 ); Console.WriteLine( f3( 5 ) );
public static class CurryMethodExtensions { public static Func< C, R > Partial< A, B, C, R >( this Func< A, B, C, R > f, A a, B b ) { return c => f( a, b, c ); } }
Func< int, int, int, int > sumNumbers = ( x, y, z ) => x + y + z; Func< int, int > f4 = sumNumbers.Partial( 3, 4 ); Console.WriteLine( f4( 5 ) );
WeakReference
var obj = new WeakReferenceTest { FirstName = "Vahid" }; var w = new WeakReference(obj); obj = null; GC.Collect(); var weakReferenceTest = w.Target as WeakReferenceTest; if ( weakReferenceTest != null ) Console.WriteLine( weakReferenceTest.FirstName );
Lazy<T>
public abstract class ThreadSafeLazyBaseSingleton< T > where T : new() { static readonly Lazy< T > lazy = new Lazy< T >( () => new T() ); public static T Instance => lazy.Value; }
BigInteger
var positiveString = "91389681247993671255433422114345532000000"; var negativeString = "-9031583741089631207100208803453423537140000"; var posBigInt = BigInteger.Parse( positiveString ); Console.WriteLine( posBigInt ); var negBigInt = BigInteger.Parse( negativeString ); Console.WriteLine( negBigInt );
- Class Library (.NET Framework)
- Class Library (.NET Standard)
- Class Library (.NET Core)
+ این مطلب هم ختم کلام است: WCF Is Dead and Web API Is Dying – Long Live MVC 6! (برای کسانیکه به دنبال انتخاب فناوریهای آینده دار هستند)
برنامه API Portability Analyzer
ساخت افزونه در سی شارپ قسمت دوم
بخش اول این سری آموزشی را از اینجا می توانید مشاهده کنید.