فلسفه وجودی بخش finally در try catch چیست؟
- اینکه شما بروز یک مشکل رو با یک عدد منفی از یک متد بازگشت میدید یعنی هنوز دید زبان C رو دارید. در دات نت وجود استثناءها دقیقا برای ننوشتن return 0 یا -1 و شبیه به آن هست. در این حالت برنامه خودکار در هر سطحی که باشد، ادامهاش متوقف میشه و نیازی نیست تا مدام خروجی یک متد رو چک کرد.
- اینکه در یک متد کانکشنی برقرار شده و بسته شده یعنی ضعف کپسوله سازی مفاهیم ADO.NET. نباید این مسایل رو مدام در تمام متدها تکرار کرد. میشه یک متد عمومی ExecSQL درست کرد بجای تکرار مدام یک سری کد.
- یک سری از اشیاء اینترفیس IDisposable رو پیاده سازی میکنند مثل همین شیء اتصالی که ذکر شد. در این حالت میشه از using استفاده کرد بجای try/finally و اون وقت به دوتا using نیاز خواهید داشت یعنی شیء Command هم نیاز به try/finally داره.
public class Student { [JsonPropertyName("id")] public int Id { get; set; } [JsonPropertyName("name")] public string Name { get; set; } } public class WeatherForecast { [Required] public int TemperatureC { get; set; } [MinLength(50)] public string Summary { get; set; } }
روش متداول ارسال نوعها به attributes تا پیش از C# 11
تا پیش از C# 11، روش پیاده سازی یک attribute جنریک که بتواند با انواع و اقسام نوعها کار کند، به صورت زیر است:
- ارسال یک پارامتر از نوع System.Type به سازندهی attribute
- تعریف خاصیتی مانند ParamType در صورت نیاز؛ تا مشخص کند که چه نوعی به سازندهی attribute ارسال شدهاست. مانند مثال فرضی زیر:
[AttributeUsage(AttributeTargets.Class)] public class CustomDoNothingAttribute: Attribute { // Note the type parameter in the constructor public CustomDoNothingAttribute(Type t) { ParamType = t; } public Type ParamType { get; } }
[CustomDoNothing(typeof(string))] public class Student { public int Id { get; set; } public string Name { get; set; } }
امکان تعریف ویژگیهای جنریک در C# 11
C# 11 به همراه پیشتیبانی از generic attributes ارائه شدهاست. بنابراین اینبار بجای ارسال پارمتری از نوع Type به سازندهی ویژگی، میتوان کلاس آن attribute را به صورت جنریک تعریف کنیم که میتواند یک یا چندین نوع را به عنوان پارامتر بپذیرد. بنابراین مثال قبل در C# 11 به صورت زیر بازنویسی میشود:
[AttributeUsage(AttributeTargets.Class)] public class CustomDoNothingAttribute<T> : Attribute where T : class { public T ParamType { get; } } [CustomDoNothing<string>] public class Student { public int Id { get; set; } public string Name { get; set; } }
و اگر نیاز به تعیین چند نوع بود، باید خاصیت AllowMultiple نحوهی استفاده از ویژگی را به true تنظیم کرد:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class DecorateAttribute<T> : Attribute where T : class { // .... }
[Decorate<LoggerDecorator>] [Decorate<TimerDecorator>] public class SimpleWorker { // .... }
محدودیتهای انتخاب نوعها در ویژگیهای جنریک C# 11
در ویژگیهای جنریک نمیتوان از نوعهای زیر استفاده کرد (همان محدودیتهای typeof، در اینجا هم برقرار هستند):
- نوعهای dynamic
- nullable reference types مانند ?string
- نوعهای tuple تعریف شدهی به کمک C# tuple syntax مانند (int x, int y)
چون این نوعها به همراه یکسری metadata annotations هستند که صرفا بیانگر توضیحی اضافی در مورد نوع بکارگرفته شده هستند و در صورت نیاز، بجای آنها میتوانید از نوعهای زیر استفاده کنید:
- از object بجای dynamic
- از string بجای ?string
- از <ValueTuple<int, int بجای (int X, int Y)
همچنین در زمان استفادهی از یک ویژگی جنریک، باید نوع مورد استفاده، کاملا مشخص و در اصطلاح fully constructed باشد:
public class GenericAttribute<T> : Attribute { } public class GenericType<T> { [GenericAttribute<T>] // Not allowed! generic attributes must be fully constructed types. public string Method1() => default; [GenericAttribute<string>] public string Method2() => default; }
پشت صحنه Bower بخش اول
طراحی رابط کاربری - راهنمایی فنی
بله. اگر حذف نشود، تمام اعمال را باز هم لاگ میکند که روی کارآیی تاثیر منفی خواهد گذاشت.
نگارش نهایی NET Core 3.0. منتشر شد
We’re excited to announce the release of .NET Core 3.0. It includes many improvements, including adding Windows Forms and WPF, adding new JSON APIs, support for ARM64 and improving performance across the board. C# 8 is also part of this release, which includes nullable, async streams, and more patterns. F# 4.7 is included, and focused on relaxing syntax and targeting .NET Standard 2.0. You can start updating existing projects to target .NET Core 3.0 today. The release is compatible with previous versions, making updating easy.
چندی قبل مطلبی را در این سایت در مورد معرفی الگویی که توسط آن میتوان اعمال غیر همزمان را به صورت پی در پی انجام داد، مطالعه کردید:
و بحث اصلی مطالب فوق هم این است:
"در برنامه نویسی متداول همیشه عادت داریم که اعمال به صورت A –> B –> C انجام شوند. اما در Async programming ممکن است ابتدا C انجام شود، سپس A و بعد B یا هر حالت دیگری صرفنظر از تقدم و تاخر آنها در حین معرفی متدهای مرتبط در یک قطعه کد. همچنین میزان خوانایی این نوع کدنویسی نیز مطلوب نیست...."
خبر خوش آن است که پشتیبانی از این نوع مدل پی در پی برنامه نویسی در نگارشهای بعدی سی شارپ و VB.NET اضافه شده است.
لیستی از مقالات منتشر شده در این مورد را در ادامه ملاحظه خواهید کرد:
علاوه بر آن یک سری ویدیوی مرتبط با این بحث نیز منتشر شده است:
Value
// Behavior 1 object obj = null; bool objValueEqual = obj.Equals(null); // Behavior 2 object obj = null; Type objType = obj.GetType(); // Behavior 3 string str = (string)null; bool strType = str is string; // Behavior 4 int num = 5; Nullable<int> nullableNum = 5; bool typeEqual = num.GetType() == nullableNum.GetType(); // Behavior 5 Type inType = typeof(int); Type nullableIntType = typeof(Nullable<int>); bool typeEqual = inType == nullableIntType;
- در رفتار اول هرچند که متد Equals از شی null در دسترس است و با مقدار null مقایسه شده اما در زمان اجرا پیغام خطای NullReferenceException را خواهیم داشت.
- در رفتار دوم هم پیغام خطا را خواهیم داشت. شئ با مقدار null، در زمان اجرا هیچ نوعی را برنمیگرداند.
- در رفتار سوم هر چند که مقدار null صریحا به رشته تبدیل شده و برای چاپ متغیر str پیام خطایی را نخواهیم داشت، اما متغیر strType در خروجی، false خواهد بود. همانطور که در رفتار دوم گفته شد، شیء با مقدار null هیچ نوعی را برنمیگرداند.
- خروجی رفتار چهارم true خواهد بود. به این صورت که هر دو از نوع System.int32 خواهند بود.
- در رفتار پنجم اگر از نوعها، خروجی جداگانه بگیریم، خواهیم دیدکه نوع int از System.int32 و <Nullable<int از نوع System.Nullable`1[System.Int32] میباشند، در نتیجه خروجی false است. اشیای nullable بعد از اینکه مقداری مشخص را دریافت کردند، به صورت یک شیء غیر nullable رفتار خواهند کرد.
مدیریت مقادیر null در سربارگذاری متدها
static void Main(string[] args) { Console.WriteLine(Method(null)); Console.ReadLine(); } private static string Method(object obj) { return "Object parameter"; } private static string Method(string str) { return "String parameter"; }
رفتارهای ()Math.Round
var rounded = Math.Round(1.5); // 2 var rounded = Math.Round(2.5); // 2 var rounded = Math.Round(2.5, MidpointRounding.ToEven); // 2 var rounded = Math.Round(2.5, MidpointRounding.AwayFromZero); // 3 var value = 1.4f; var rounded = Math.Round(value + 0.1f); // 1
مقدار دهی اولیه کلاسها
- فیلدهای استاتیک (زمانیکه کلاس برای اولین بار در دسترس قرار میگیرد)
- سازنده استاتیک (زمانیکه کلاس برای اولین بار در دسترس قرار میگیرد)
- فیلدهایی از کلاس که در نمونه ساخته شده در دسترس قرار میگیرند.
- سازنده کلاس که در زمان ایجاد یک نمونه از کلاس در دسترس قرار میگیرد.
public static class Config { public static bool ThrowException { get; set; } = true; } public class FailingClass { static FailingClass() { if (Config.ThrowException) { throw new InvalidOperationException(); } } }
try { var failedInstance = new FailingClass(); } catch (TypeInitializationException) { } Config.ThrowException = false; var instance = new FailingClass();
public class BaseClass { { public BaseClass() { VirtualMethod(1); } public virtual int VirtualMethod(int dividend) { return dividend / 1; } } public class DerivedClass : BaseClass { int divisor; public DerivedClass() { divisor = 1; } public override int VirtualMethod(int dividend) { return base.VirtualMethod(dividend / divisor); } }
چند ریختی
class Program { static void Main(string[] args) { var instance = new DerivedClass(); var result = instance.Method(); result = ((BaseClass)instance).Method(); Console.WriteLine(instance + " -> " + result); // Derived Class ... -> Method in BaseClass Console.ReadLine(); } } public class BaseClass { public virtual string Method() { return "Method in BaseClass"; } } public class DerivedClass : BaseClass { public override string ToString() { return "Derived Class ... "; } public new string Method() { return "Method in DerivedClass"; } }
class Program { static void Main(string[] args) { var instance = new DerivedClass(); var result = instance.Method(); // -> Method in DerivedClass result = ((IInterface)instance).Method(); // -> Method belonging to IInterface Console.WriteLine(result); Console.ReadLine(); } } public interface IInterface { string Method(); } public class DerivedClass : IInterface { public string Method() { return "Method in DerivedClass"; } string IInterface.Method() { return "Method belonging to IInterface"; } }
Iterators
private IEnumerable<int> GetEnumerable(StringBuilder log) { using (var test = new Test(log)) { return Enumerable.Range(1, 5); } }
var log = new StringBuilder(); foreach (var number in GetEnumerable(log)) { log.AppendLine($"{number}"); }
Created Disposed 1 2 3 4 5
using (var test = new Test(log)) { foreach (var i in Enumerable.Range(1,5)) { yield return i; } }
Created 1 2 3 4 5 Disposed