3 min. read

שימוש במחלקות בסיס וממשקים

אל:

1
2
3
4
5
6
7
8
public class Serializer
{
public byte[] Serialize(object obj)
{
throw new NotImplementedException();
}
}

עדיף:

1
2
3
4
public interface ISerializer
{
byte[] Serialize(object obj);
}

ניתן ליצור מופעים ממחלקות ולכן אם המחלקה לא אבסרקטית או בנויה כממשק אז למופע שלה לא יהיה ערך אמיתי,

העדיפו פונקציות גנריות על פני object

אל:

1
2
3
4
public interface ISerializer
{
byte[] Serialize(object obj);
}

עדיף:

1
2
3
4
public interface ISerializer
{
byte[] Serialize<T>(T obj);
}

הסיבה לכך היא השימוש ב-boxing.
כאשר int נאסף ע”י ה-CLR הוא צריך להיות מיוצג כמחלקה כדי לתאר אותו כאובייקט.
בגלל ההבדל בין Value type ל-Reference Type.
כאשר משתמשים בקוד גנרי נוצרים פונקציות ספציפיות עבור סוגי המשתנים.

השתמשו ב-Record במקום Class

אל:

1
2
3
4
public class Person
{
public string Name {get;set;}
}

עדיף:

1
public record Person(string Name);

או:

1
2
3
4
public record Person
{
public string Name { get; set; } = default!;
};

ב-C# 9.0 הוסיפו record אשר עוזר לממש מחלקות מודלים בקלות.

העדיפו IEnumerable על פני רשימות קונקרטיות

אל:

1
2
3
4
public class Namer
{
public List<string> SuggestNames() { ... }
}

עדיף:

1
2
3
4
public class Namer
{
public IEnumerable<string> SuggestNames() { ... }
}

השימוש ברשימות מכריח את הקוד להשתמש במחלקה קונקרטית של רשימה ובכך מכריח שימוש באלגוריתם ספציפי.
אם נרצה לבנות את הקוד שלנו להשתמש בסוג אחר:
רשימה מקושרת, מערך, רשימה מסודרת או משהו אחר - לא נוכל להשתמש בזה מבלי לאבד את השימוש באלגוריתם.
כמו כן זה מכריח את המשתמש ליצור מופעים חדשים ואף להעתיק את הערכים, במידה ומס’ הערכים עצום זה ייעלה לנו בזיכרון וביצועים.

העדיפו שימוש ב-Readonly

אל:

1
2
3
4
5
6
7
8
9
public class ServiceClass
{
private ICaller mCaller;

ServiceClass(ICaller caller)
{
mCaller= caller;
}
}

עדיף:

1
2
3
4
5
6
7
8
9
public class ServiceClass
{
private readonly ICaller mCaller;

ServiceClass(ICaller caller)
{
mCaller= caller;
}
}

במידה ומשתנה במחלקה יהיה מאותחל פעם אחת בלבד - נרצה להימנע מתאחול מחדש של המשתנה.

השתמשו בפורמט במקום פונקציות חיבור מחרוזות, או StringBuilder

אל:

1
2
3
string a = "Hello";
string b = " World";
Console.WriteLine(a + b + "!");

עדיף:

1
2
3
string a = "Hello";
string b = "World";
Console.WriteLine($"{a} {b}!");

או

1
2
3
4
5
6
StringBuilder builder = new StringBuilder();
builder.Append("Hello");
builder.Append(" World");
builder.Append("!");

Console.WriteLine(builder.ToString());

הימנעו מ-is או as

אל:

1
2
3
4
5
6
7
8
9
10
11
object MyObj = fromObject;

if(myObj is Developer)
{
Developer d = myObj as Developer;
if(d.YearsOfProgramming > 5)
{
Console.WriteLine($"{d.name} is a senior dev!");
}
// Do something with d....
}

עדיף:

1
2
3
4
5
6
7
8
9
10
11
object MyObj = fromObject;

var description = myObj switch
{
Developer d when d.YearsOfProgramming is >= 5 => $"{d.name} is a senior dev!",
Developer d when d.YearsOfProgramming is < 5 => $"{d.name} is a junior dev!",
Person p => $"{p.Name} is not a developer",
_ => "Not a person"
};

Console.WriteLine(description);

השימוש החדש בswitch עם pattern matching הוא כלי חזק ויעיל לבניית בדיקות.

בכללי אני מעדיף לא להשתמש בבדיקת Type אלה להשתמש בהם בעזרת תבנית האסטרגיה.
אבל במידה ואתם ממש צריכים את זה, ניתן להשתמש בזה באופן הזה :)

תשדרגו את ה-Attributeים שלכם לגנריים !

אל:

1
2
[TypeAttribute(typeof(string))]
public string Method() => default;

עדיף:

1
2
[GenericAttribute<string>()]
public string Method() => default;

C# 11.0 הוסיפו פיצ’ר לאפשר Attribute גנרי!
כדאי להשתמש בזה כי שימוש ב-typeof איטי יותר.

השתמשו ב-ref struct כדי להימנע משימוש ב-Heap

אל:

1
2
3
4
struct Data
{
public Span<byte> Image;
}

עדיף:

1
2
3
4
ref struct Data
{
public Span<byte> Image;
}

קיימים לפיצ’ר מגבלות רבות אך אם אתם רוצים להימנע מהמשתנה שלכם לעבור boxing ולגרוע מביצועים - זו הדרך לבצע את זה.

העדיפו ValueTask על Task בקוד הדורש ביצועים

אל:

1
public Task<byte[]> Read(Stream s);

עדיף:

1
2
public ValueTask<byte[]> Read(Stream s);

במקרים שלא צריך לבצע קריאה ל-Task כמו כאשר התוצאה קיימת לנו כבר, אז נוכל לגרוע את האלוקציה ל-Task.
במידה ואתם משתמשים ב-ValueTask<T> נחסוך את ההקצאה בכך לא נגרע מהביצועים!


אהבתם? מוזמנים להביע תמיכה כאן: כוס קפה