برنامه نویسی

روش درک مخفی کردن و ظهور در C#: یک مشکل در دنیای واقعی حل شد

من به تازگی در کار خود با مشکلی روبرو شده ام که بسته به رابط ها ، در اطراف فرهنگ لغت های پرجمعیت می چرخید ، اما یکی از انواع مشتق شده در مجموعه مورد انتظار نشان داده نشده است. بعد از حفر عمیق تر ، من به مفهومی رسیدم که برای من جدید بود: روش مخفی کردنبشر این باعث می شد کلاس مشتق من برای رابط نامناسب باشد. من با روش اصلی آشنا بودم ، اما قبلاً هرگز با روش مخفی کردن روبرو نشده بودم.

در این مقاله ، من مشکلی را که با آن روبرو شدم ، چگونه آن را حل کردم و مفاهیم و تفاوت های بین مخفی کردن روش و روش مهم را توضیح خواهم داد.

مشکل

من در حال کار بر روی سیستمی بودم که کارتها توسط کلاسهای اجرا نشان داده می شدند ICard رابط کارت ها به طور معمول پیاده سازی می کنند ICard به طور غیر مستقیم از طریق رابط های دیگر ، مانند ICardWithHighlight وت ICardWithRelatedCards، که گسترش می یابد ICardبشر

public interface ICard
{
    string GetCardId();
}

public interface ICardWithHighlight : ICard
{
    HighlightColor ShouldHighlight(Card card);
}

public interface ICardWithRelatedCards : ICard
{
    bool ShouldShowForOpponent(Player opponent);
    List<Card?> GetRelatedCards(Player player);
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

سیستم استفاده می کند بازتاب برای بارگیری پویا تمام کلاس های کارت و بررسی اینکه کدام رابط را اجرا می کنند. هدف این است که فرهنگ لغت ها را با نمونه های کارت جمع کنید ، که توسط منحصر به فرد آنها مشخص شده است CardIdبشر

کارت Arcanologist دارای 2 شناسه مختلف است. بنابراین ، دارای 2 کلاس کارت است: Arcanologist وت ArcanologistCore، هر اجرا GetCardId() با ارزش مربوطه از آنجا که آنها به همان کارت مراجعه می کنند ، من از وراثت استفاده کردم تا آنها ShouldHighlight() روش در هر دو کلاس سازگار است. با این حال ، من با یک مشکل روبرو شدم: کلاس مشتق شده ArcanologistCore به HighlightCards فرهنگ لغت ، حتی اگر به نظر می رسید یک اجرای معتبر از آن است ICardWithHighlightبشر

public class RelatedCardsManager
{
    private Dictionary<string, ICardWithRelatedCards>? _relatedCards;
    private Dictionary<string, ICardWithHighlight>? _highlightCards;

    public Dictionary<string, ICardWithRelatedCards> RelatedCards => _relatedCards ??= InitializeRelatedCards();
    public Dictionary<string, ICardWithHighlight> HighlightCards  => _highlightCards ??= InitializeHighlightCards();

    private Dictionary<string, ICardWithRelatedCards> InitializeRelatedCards()
    {
        var (relatedCardsDict, highlightCardsDict ) = InitializeCards();
        _highlightCards = highlightCardsDict;
        return relatedCardsDict;
    }

    private Dictionary<string, ICardWithHighlight> InitializeHighlightCards()
    {
        var (relatedCardsDict, highlightCardsDict ) = InitializeCards();
        _relatedCards = relatedCardsDict;
        return highlightCardsDict;
    }

    private (Dictionary<string, ICardWithRelatedCards>, Dictionary<string, ICardWithHighlight>) InitializeCards()
    {
        var cards = Assembly.GetAssembly(typeof(ICard)).GetTypes()
            .Where(t => t.IsClass && !t.IsAbstract && typeof(ICard).IsAssignableFrom(t));

        var relatedCardsDict = new Dictionary<string, ICardWithRelatedCards>();
        var highlightCardsDict = new Dictionary<string, ICardWithHighlight>();

        foreach(var card in cards)
        {
            var cardInstance = Activator.CreateInstance(card) as ICard;

            if(cardInstance is ICardWithRelatedCards relatedCard)
            {
                relatedCardsDict[relatedCard.GetCardId()] = relatedCard;
            }

            if(cardInstance is ICardWithHighlight highlightCard)
            {
                highlightCardsDict[highlightCard.GetCardId()] = highlightCard;
            }
        }

        return (relatedCardsDict, highlightCardsDict);
    }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در کد بالا: – بازتاب برای بارگیری انواع موجود در مونتاژ که پیاده سازی می شود استفاده می شود ICard رابط – ما بررسی می کنیم که آیا نوع پیاده سازی را اجرا می کند ICardWithHighlight یا ICardWithRelatedCards برای اضافه کردن آن به فرهنگ لغت مناسب. – تنبلی فرهنگ لغت ها را آغاز کنید ، و هنگامی که یک نفر اولیه می شود ، دیگری را نیز آغاز می کند.

حالا ، بیایید نگاهی به Arcanologist وت ArcanologistCore کلاس ها:

public class Arcanologist : ICardWithHighlight
{
    public string GetCardId() => HearthDb.CardIds.Collectible.Mage.Arcanologist;

    public HighlightColor ShouldHighlight(Card card) =>
        HighlightColorHelper.GetHighlightColor(card.GetTag(GameTag.SECRET) > 0);
}

public class ArcanologistCore : Arcanologist
{
    public new string GetCardId() => HearthDb.CardIds.Collectible.Mage.ArcanologistCore;
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

موضوع

مشکل هنگامی رخ داد که ArcanologistCore در HighlightCards فرهنگ لغت حتی ArcanologistCore به درستی اجرا شده است ICardWithHighlight و خودش را داشت GetCardId() روش ، هنگام جمع آوری فرهنگ لغت هنوز نادیده گرفته می شد.

اولین راه حل من اضافه کردن دستی بود ICardWithHighlight به ArcanologistCore کلاس. این کار کرد و کارت در فرهنگ لغت ظاهر شد.

public class ArcanologistCore : Arcanologist, ICardWithHighlight
{
    public new string GetCardId() => HearthDb.CardIds.Collectible.Mage.ArcanologistCore;
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اما من از این راه حل راضی نبودم. من همیشه می دانستم که در OOP وقتی کلاس دیگری را گسترش می دهد ، باید تمام رابط های آن را اجرا کند ، بنابراین چرا باید صریحاً بنویسم که کلاس مشتق شده من در حال اجرای آن رابط است؟ بنابراین من شروع به پاسخ به این کار می کنم و آن را پیدا کردم. نامیده می شود روش مخفی کردنبشر

پنهان کردن روش و روش مهم چیست؟

در C#، روش مخفی کردن هنگامی اتفاق می افتد که یک کلاس مشتق شده روشی را با همان نام به عنوان یک روش در کلاس پایه تعریف کند ، اما بدون استفاده از آن override کلمه کلیدی این باعث می شود روش کلاس مشتق شده روش کلاس پایه را پنهان کند. هنگام استفاده از روش مخفی کردن روش ، روش کلاس پایه خوانده نمی شود – در عوض ، از روش در کلاس مشتق شده فقط در صورتی استفاده می شود که مرجع به طور خاص از نوع مشتق شده باشد. این روش ، از آنجا GetCardId() در کلاس پایه پنهان بود ، ArcanologistCore دیگر به طور کامل اجرا نشده است ICard رابط ، و در نتیجه ، آن را اجرا نکرد ICardWithHighlight یا

روش مهماز طرف دیگر ، هنگامی اتفاق می افتد که یک کلاس مشتق شده از کلمه کلیدی Override استفاده کند تا اجرای خود را از یک روش از کلاس پایه فراهم کند. این تضمین می کند که روش در کلاس مشتق شده فراخوانی می شود ، حتی اگر مرجع از نوع کلاس پایه باشد.

راه حل

راه حل ساده بود: به جای استفاده از new کلمه کلیدی در GetCardId() در ArcanologistCore، من نیاز به استفاده داشتم override برای اینکه به درستی روش را از کلاس پایه نادیده بگیرید. این تضمین می کند که وقتی یک شی از نوع است ArcanologistCore به عنوان یک ارجاع شده است ICardWithHighlight، روش بیش از حد نامیده می شود و اجازه می دهد کارت به فرهنگ لغت اضافه شود. من همچنین مجبور شدم روش کلاس پایه را به عنوان علامت گذاری کنم virtual برای گفتن C# که این روش می تواند نادیده گرفته شود.

در اینجا اجرای اصلاح شده است:

public class Arcanologist : ICardWithHighlight
{
    public virtual string GetCardId() => HearthDb.CardIds.Collectible.Mage.Arcanologist;

    public HighlightColor ShouldHighlight(Card card) =>
        HighlightColorHelper.GetHighlightColor(card.GetTag(GameTag.SECRET) > 0);
}

public class ArcanologistCore : Arcanologist
{
    public override string GetCardId() => HearthDb.CardIds.Collectible.Mage.ArcanologistCore;
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

پایان

بعد از تغییر new کلمه کلیدی به override در کلاس مشتق شده ، کارت به درستی اضافه شد HighlightCards فرهنگ لغت ، و مسئله حل شد. این تجربه به من کمک کرد تا تفاوت بین آن را درک کنم روش مخفی کردن وت روش مهم در C#.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا