簡體   English   中英

在重載方法中使用泛型類型

[英]Use of generic types in overloaded methods

我有一個通用的方法:

public bool DoSomething<T>(T item) where T: IBase
{
    return DoSomethingSpecific(item);
}

public bool DoSomethingSpecific(IBase item)
{
    return true;
}

public bool DoSomethingSpecific(IAdvanced item)
{
    return false;
}

請注意,IAdvanced接口從IBase接口派生/繼承。

我發現如果我調用DoSomething,其中項目的類型為IAdvanced,它仍然總是返回false。 我不明白這一點。 我知道,因為IAdvanced是一個類型IBase(因為它是這個接口的子代),它可能會導致DoSomethingSpecific方法的2個重載類型之間的混淆。 但是,正如我對有限的C#知識所理解的那樣,應該在這里選擇IAdvanced方法。 這是我如何得出這個結論的一個例子:

public class Advanced: IAdvanced
{

   public void CallMethod()
   {
      DoSomething(this);
   }
}

這導致了真正的價值。

但是,如果我這樣做:

public class Advanced: IAdvanced
{

    public void CallMethod()
    {
       DoSomethingSpecific(this);
    }
}

它返回false,這是我所期望的。

我不得不說我之前從未使用過仿制葯。 我曾試過,但總是陷入這樣的情況,然后完全沒有看到使用泛型的意義(除了樹和鏈表之類的數據結構)。

這次我決定來這里尋求一些建議。 我試圖做的是否有明顯的問題? 嘗試做我在這里忙的事情可能沒有意義嗎?

我無法重現這一點,這意味着其他可能正在發生。 我懷疑你實際上想說它總是回歸真實 這就是我在這里看到的:

using System;

public interface IBase {}
public interface IAdvanced : IBase {}

public class Base : IBase {}
public class Advanced : IAdvanced {}

class Test
{
    public static bool DoSomething<T>(T item) where T: IBase
    {
        return DoSomethingSpecific(item);
    }

    public static bool DoSomethingSpecific(IBase item)
    {
        return true;
    }

    public static bool DoSomethingSpecific(IAdvanced item)
    {
        return false;
    }

    static void Main()
    {
        Console.WriteLine(DoSomething(new Base()));     // True
        Console.WriteLine(DoSomething(new Advanced())); // True
    }    
}

現在你也寫:

我知道,因為IAdvanced是一個類型IBase(因為它是這個接口的子代),它可能會導致DoSomethingSpecific方法的2個重載類型之間的混淆。 但是,正如我對有限的C#知識所理解的那樣,應該在這里選擇IAdvanced方法。

當然,你應該期望返回false - 而我希望返回true

你看, DoSomething<T>的重載決議是在編譯該方法時確定的。 這種選擇只做一次 - 對於每個不同的T都不是一次。 因此,如果您查看已編譯的IL中的DoSomething<T> ,您將看到對DoSomethingSpecific(IBase)的調用,而不是 DoSomethingSpecific(IAdvanced) 這里沒有多態性。

至於如何“修復”這個 - 你需要更詳細地解釋你真正想要實現的目標。 特別是,如果你有這個代碼,你會想要發生什么:

IBase x = new AdvancedImplementation();
DoSomething(x);

這里的T將是IBase ,但該將指IAdvanced的實現。 如果你想在這種情況下執行DoSomethingSpecific(IAdvanced) ,並且你正在使用C#4,那么你可以使用動態類型:

public static bool DoSomething(IBase item)
{
    dynamic dynamicItem = item;
    // Dispatch dynamically based on execution-time type
    return DoSomethingSpecific(dynamicItem);
}

請注意該方法不再需要通用 - 它不會帶來任何好處。

另一方面,如果您想要決定僅基於T調用哪個,則需要使用類似ivowiblo的解決方案。

就個人而言,我會盡量避免這兩種解決方案 - 我通常會發現這種事情是設計的一種症狀,可以通過其他方式得到改善。

我會刪除編譯時檢查並使其成為運行時:

public bool DoSomething(IBase item)
{
    var itemAdvanced = item as IAdvanced;
    if (itemAdvanced != null)
        return DoSomethingSpecific(itemAdvanced);
    else
        return DoSomethingSpecific(item);
}

原因是如果你的調用者只是靜態地知道對象是一個IBase ,但是在運行時它是一個IAdvanced ,不是首選將它當作IAdvanced嗎? 這可能也是做你想做的最快的方式。 如果你看到需要,我只會采用dynamic方法,例如因為可能存在大量不同的方法。

據他所知,這是一個IBase。 編譯器需要確定你調用哪種方法,這就是它總是選擇那個方法的原因。

一個骯臟的技巧將是這樣做:

public static bool DoSomething<T>(T item) where T: IBase
{
    var isAdvanced = typeof(IAdvanced).IsAssignableFrom(typeof(T));
    return isAdvanced ? DoSomethingSpecific((IAdvanced)item) : DoSomethingSpecific(item);
}

另一種方法是使用Double-Dispatch / Visitor模式:

public interface IDoSomethingVisitor {
    bool DoSomethingSpecific(IBase base);
    bool DoSomethingSpecific(IAdvanced adv);
}

DoSomething方法將在您的IBase界面中:

public interface IBase{
    void DoSomething(IDoSomethingVisitor visitor);
}

在您的實施中:

public class Base : IBase
{
   public bool DoSomething(IDoSomethingVisitor visitor)
   {
      visitor.DoSomething(this);
   }
}

public class Advanced : IAdvanced
{
   public bool DoSomething(IDoSomethingVisitor visitor)
   {
      visitor.DoSomething(this);
   }
}

在這種情況下,使用純繼承解決問題。 實際的實例是解析調用哪個方法的實例。 不,如果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM