الميزات المخفية من C#؟




hidden-features (20)

من CLR عبر C # :

عند تطبيع السلاسل ، يوصى بشدة باستخدام ToUpperInvariant بدلاً من ToLowerInvariant لأن Microsoft قامت بتحسين التعليمات البرمجية لإجراء عمليات المقارنة الكبيرة .

أتذكر مرة واحدة أن زميل العمل الخاص بي دائماً غيّر السلاسل إلى الأحرف الكبيرة قبل المقارنة. لقد تساءلت دائمًا لماذا يفعل ذلك لأنني أشعر أنه من "الطبيعي" أن يتم التحويل إلى الأحرف الصغيرة أولاً. بعد قراءة الكتاب الآن أعرف لماذا.

جاء ذلك في ذهني بعد أن تعلمت ما يلي من هذا السؤال :

where T : struct

نحن ، مطوري C # ، جميعنا نعرف أساسيات C #. أعني الإعلانات ، الشروط ، الحلقات ، المشغلين ، إلخ.

البعض منا حتى يتقن أشياء مثل Generics ، وأنواع المجهول ، lambdas ، LINQ ، ...

ولكن ما هي أكثر الميزات أو الحيل المخفية لـ C # حتى المشجعين C # والمدمنين والخبراء بالكاد يعرفون؟

فيما يلي السمات المعلنة حتى الآن:


الكلمات الدالة

سمات

بناء الجملة

  • ?? (coalesce nulls) المشغل من قبل kokos
  • عدد البزات التي كتبها نيك بيراردي
  • where T:new لارس Mæhlum
  • الدنا الضمني بواسطة Keith
  • لامبداس المعلمة من قبل Keith
  • خصائص السيارات بواسطة Keith
  • الاسم المستعار الاسم المستعار بواسطة Keith
  • حرفي سلسلة الحرفية مع @ بواسطة Patrick
  • قيم enum lfoust
  • variablenames by marxidad
  • مشغلي event قبل marxidad
  • تنسيق أقواس سلسلة من Portman
  • معدّل الوصول إلى accessororor بواسطة xanadont
  • عامل شرطي (ثلاثي) ( ?: JasonS بواسطة JasonS
  • مشغلات unchecked وغير unchecked قبل Binoj Antony
  • المشغلين implicit and explicit قبل Flory

سمات اللغة

ميزات Visual Studio

الإطار

الطرق والخصائص

  • أسلوب KiwiBastard String.IsNullOrEmpty() بواسطة KiwiBastard
  • طريقة List.ForEach() بواسطة KiwiBastard
  • BeginInvoke() ، EndInvoke() طرق من قبل Will Dean
  • Nullable<T>.HasValue و Nullable<T>.HasValue Nullable<T>.Value خصائص Nullable<T>.Value بواسطة Rismo
  • طريقة GetValueOrDefault بواسطة John Sheehan

نصائح وخدع

  • طريقة لطيفة لمعاملي الحدث من قبل أندرياس HR Nilsson
  • مقارنات الأحرف الكبيرة بواسطة John
  • الوصول إلى أنواع مجهولة بدون انعكاس بواسطة dp
  • طريقة سريعة لتجديد خصائص جمع بكسل من قبل Will
  • تشبه جافا سكريبت-مثل وظائف مضمنة المجهول من قبل roosteronacid

آخر


يقوم @ بإعلام المحول البرمجي بتجاهل أي أحرف إبطال في سلسلة.

أردت فقط توضيح هذه العبارة ... لا تخبرها بتجاهل أحرف الهروب ، بل إنها تخبر المحول البرمجي أن يفسر السلسلة على أنها حرفية.

اذا كنت تمتلك

string s = @"cat
             dog
             fish"

ستتم طباعتها بالفعل (لاحظ أنها تتضمن المسافة البيضاء المستخدمة في المسافة البادئة):

cat
             dog
             fish

  1. ?? - coalescing operator
  2. using ( statement / directive ) - great keyword that can be used for more than just calling Dispose
  3. readonly - should be used more
  4. netmodules - too bad there's no support in Visual Studio

" yield " سيتبادر إلى ذهني. بعض السمات مثل DefaultValueAttribute هي أيضا من بين المفضلة لدي.

الكلمة " var " معروفة أكثر قليلاً ، ولكن يمكنك استخدامها في تطبيقات .NET 2.0 كذلك (طالما أنك تستخدم مترجم NET 3.5 وتعيينه لإخراج رمز 2.0) لا يبدو معروفاً حسنا.

تحرير: kokos ، شكرا لافتا إلى؟ المشغل ، وهذا في الواقع مفيد حقا. نظرًا لأنه من الصعب بعض الشيء بالنسبة لـ google (حيث يتم تجاهلها فقط) ، فإليك صفحة وثائق MSDN الخاصة بهذا المشغل: ?? ??


أعتقد أن أحد أكثر ميزات C # (.NET 3.5) الأقل تقديراً وأقل شهرةً هي " أشجار التعبير" ، خاصة عند دمجها مع Generics و Lambdas. هذا هو نهج لإنشاء API التي تستخدمها المكتبات الأحدث مثل NInject و Moq.

على سبيل المثال ، لنفترض أنني أريد تسجيل طريقة باستخدام واجهة برمجة التطبيقات وأن واجهة برمجة التطبيقات تحتاج إلى الحصول على اسم الأسلوب

نظرا لهذه الفئة:

public class MyClass
{
     public void SomeMethod() { /* Do Something */ }
}

في السابق ، كان من الشائع جدًا رؤية المطورين يقومون بذلك باستخدام السلاسل والأنواع (أو أي شيء آخر يستند إلى حد كبير):

RegisterMethod(typeof(MyClass), "SomeMethod");

حسنا ، هذا يمتص بسبب عدم وجود الكتابة القوية. ماذا لو قمت بإعادة تسمية "SomeMethod"؟ الآن ، في 3.5 ، يمكنني القيام بذلك بطريقة مطبوعة بشدة:

RegisterMethod<MyClass>(cl => cl.SomeMethod());

في أي فئة RegisterMethod يستخدم Expression<Action<T>> مثل هذا:

void RegisterMethod<T>(Expression<Action<T>> action) where T : class
{
    var expression = (action.Body as MethodCallExpression);

    if (expression != null)
    {
        // TODO: Register method
        Console.WriteLine(expression.Method.Name);
    }
}

هذا هو سبب واحد كبير أنني في حالة حب مع Lambdas و Expression Trees في الوقت الحالي.


إذا كنت ترغب في الخروج من برنامجك دون الاتصال بأية برامج أو كتل في النهاية ، فاستخدم FailFast :

Environment.FailFast()

الأدوية البديلة:

using ASimpleName = Dictionary<string, Dictionary<string, List<string>>>;

يسمح لك باستخدام ASimpleName ، بدلاً من Dictionary<string, Dictionary<string, List<string>>> .

استخدمها عندما تستخدم نفس الشيء الكبير الطويل المعقّد في الكثير من الأماكن.


السمات بشكل عام ، ولكن الأهم من ذلك كله DebuggerDisplay . يوفر عليك سنوات.


خدعي المفضل هو استخدام عامل التشغيل null compelsce والأقواس لإنشاء مجموعات تلقائية لـ لي تلقائياً.

private IList<Foo> _foo;

public IList<Foo> ListOfFoo 
    { get { return _foo ?? (_foo = new List<Foo>()); } }

فيما يلي بعض الميزات C # المخفية المثيرة للاهتمام ، في شكل الكلمات الرئيسية C # غير الموثقة:

__makeref

__reftype

__refvalue

__arglist

هذه هي الكلمات الرئيسية C # غير موثقة (حتى يتعرف عليها Visual Studio!) التي تمت إضافتها إلى أكثر فعالية في الملاكمة / إزالة الصندوق قبل الأدوية. وهي تعمل بالتنسيق مع بنية System.TypedReference.

هناك أيضا __ قائمة ، والتي تستخدم لقوائم المعلمات طول متغير.

هناك شيء واحد لا يعرفه System.WeakReference عنه هو System.WeakReference - فئة مفيدة للغاية تقوم بتتبع كائن ما ولكنها تسمح لمجمع البيانات المهملة بجمعها.

ستكون الميزة "المخفية" الأكثر فائدة هي الكلمة الرئيسية لعائد العائد. إنه ليس مخفيًا حقًا ، لكن الكثير من الناس لا يعرفون عنه. بنيت LINQ على قمة هذا ؛ يسمح باستعلامات تأخير التنفيذ عن طريق إنشاء جهاز حالة ضمن الغطاء. نشرت ريموند تشن مؤخرا حول التفاصيل الداخلية ، شجاع .


لم أكن أعرف الكلمة الرئيسية "كـ" لفترة طويلة.

MyClass myObject = (MyClass) obj;

ضد

MyClass myObject = obj as MyClass;

سيتم إرجاع القيمة الثانية إذا لم يكن obj MyClass ، بدلاً من طرح استثناء فئة الإرسال.


من ريك ستراهل :

يمكنك سلسلة؟ المشغل بحيث يمكنك القيام حفنة من المقارنات الفارغة.

string result = value1 ?? value2 ?? value3 ?? String.Empty;

هناك شيئان تعجبني ، وهما الخصائص التلقائية ، حتى يمكنك تصغير الشفرة بشكل أكبر:

private string _name;
public string Name
{
    get
    {
        return _name;
    }
    set
    {
        _name = value;
    }
}

يصبح

public string Name { get; set;}

أيضا وجوه المبدئي:

Employee emp = new Employee();
emp.Name = "John Smith";
emp.StartDate = DateTime.Now();

يصبح

Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()}

lambdas ونوع inferrence تم الاستخفاف بها. يمكن أن تحتوي Lambdas على عبارات متعددة وتتضاعف ككائن مفوض متوافق تلقائيًا (فقط تأكد من تطابق التوقيع) كما في:

Console.CancelKeyPress +=
    (sender, e) => {
        Console.WriteLine("CTRL+C detected!\n");
        e.Cancel = true;
    };

لاحظ أنه ليس لديّ new CancellationEventHandler ولا يجب أن أحدد أنواع sender و e ، حيث يمكن استبعادها من الحدث. وهذا هو السبب في أن هذا أقل تعقيدًا عند كتابة delegate (blah blah) بأكمله delegate (blah blah) والذي يتطلب منك أيضًا تحديد أنواع المعلمات.

لا تحتاج Lambdas إلى إعادة أي شيء ، ونوع الاستدلال قوي للغاية في سياق مثل هذا.

و BTW ، يمكنك دائما العودة Lambdas التي تجعل Lambdas بالمعنى الوظيفي للبرمجة. على سبيل المثال ، هنا lambda الذي يجعل lambda الذي يعالج حدث Button.Click:

Func<int, int, EventHandler> makeHandler =
    (dx, dy) => (sender, e) => {
        var btn = (Button) sender;
        btn.Top += dy;
        btn.Left += dx;
    };

btnUp.Click += makeHandler(0, -1);
btnDown.Click += makeHandler(0, 1);
btnLeft.Click += makeHandler(-1, 0);
btnRight.Click += makeHandler(1, 0);

لاحظ تسلسل: (dx, dy) => (sender, e) =>

الآن هذا هو السبب في أنني سعيد لأني اخذت فئة البرمجة الوظيفية :-)

بخلاف المؤشرات في C ، أعتقد أنه الشيء الأساسي الآخر الذي يجب أن تتعلمه :-)


تجنب التحقق من معالجات الأحداث الفارغة

إضافة مفوض فارغ للأحداث في الإعلان ، قمع الحاجة إلى التحقق من الحدث دائمًا قبل أن يطلق عليه أمر رائع. مثال:

public delegate void MyClickHandler(object sender, string myValue);
public event MyClickHandler Click = delegate {}; // add empty delegate!

دعك تفعل هذا

public void DoSomething()
{
    Click(this, "foo");
}

بدلا من هذا

public void DoSomething()
{
    // Unnecessary!
    MyClickHandler click = Click;
    if (click != null) // Unnecessary! 
    {
        click(this, "foo");
    }
}

يرجى الاطلاع أيضًا على هذه المناقشة ذات الصلة ونشرة هذا المدونة بواسطة Eric Lippert حول هذا الموضوع (والسلبيات المحتملة).


@Ed, I'm a bit reticent about posting this as it's little more than nitpicking. However, I would point out that in your code sample:

MyClass c;
  if (obj is MyClass)
    c = obj as MyClass

If you're going to use 'is', why follow it up with a safe cast using 'as'? If you've ascertained that obj is indeed MyClass, a bog-standard cast:

c = (MyClass)obj

...is never going to fail.

Similarly, you could just say:

MyClass c = obj as MyClass;
if(c != null)
{
   ...
}

I don't know enough about .NET's innards to be sure, but my instincts tell me that this would cut a maximum of two type casts operations down to a maximum of one. It's hardly likely to break the processing bank either way; personally, I think the latter form looks cleaner too.


If you're trying to use curly brackets inside a String.Format expression...

int foo = 3;
string bar = "blind mice";
String.Format("{{I am in brackets!}} {0} {1}", foo, bar);
//Outputs "{I am in brackets!} 3 blind mice"

Maybe not an advanced technique, but one I see all the time that drives me crazy:

if (x == 1)
{
   x = 2;
}
else
{
   x = 3;
}

can be condensed to:

x = (x==1) ? 2 : 3;

Returning anonymous types from a method and accessing members without reflection.

// Useful? probably not.
private void foo()
{
    var user = AnonCast(GetUserTuple(), new { Name = default(string), Badges = default(int) });
    Console.WriteLine("Name: {0} Badges: {1}", user.Name, user.Badges);
}

object GetUserTuple()
{
    return new { Name = "dp", Badges = 5 };
}    

// Using the magic of Type Inference...
static T AnonCast<T>(object obj, T t)
{
   return (T) obj;
}

This one is not "hidden" so much as it is misnamed.

A lot of attention is paid to the algorithms "map", "reduce", and "filter". What most people don't realize is that .NET 3.5 added all three of these algorithms, but it gave them very SQL-ish names, based on the fact that they're part of LINQ.

"map" => Select
Transforms data from one form into another

"reduce" => Aggregate
Aggregates values into a single result

"filter" => Where
Filters data based on a criteria

The ability to use LINQ to do inline work on collections that used to take iteration and conditionals can be incredibly valuable. It's worth learning how all the LINQ extension methods can help make your code much more compact and maintainable.







hidden-features