簡體   English   中英

動態類型的靜態類型檢查不共享C#中的接口

[英]Static type-checking of dynamic types not sharing an interface in C#

假設我有一些外部類,這些類具有按約定共享簽名的方法,但未實現接口:

class A {
  public string getError();
}

class B {
  public string getError();
}

如果我想創建一個接受兩種類型對象的實用函數,可以使用dynamic

void printError(dynamic obj) {
  Console.WriteLine("Error: {0}", obj.getError());
}

但是,如果我傳遞了一些沒有getError方法的類C ,那么這將是運行時錯誤。 鑒於我不能(直接)修改AB ,有沒有一種方法可以實現這一點,從而在沒有getError方法的情況下傳遞類型將是編譯時錯誤,類似於我們在C ++模板中獲得的方法?

聽起來您有XY問題。 與其搞清楚如何使代碼的類型安全性降低,不如僅使用重載和重構?

public void PrintError(A obj) 
{
    Console.WriteLine("Error: {0}", obj.getError());
    //maybe some more logic
}

public void PrintError(B obj) 
{
    Console.WriteLine("Error: {0}", obj.getError());
    //maybe some more logic
}

上面的代碼解決了您的問題,但是不再干燥。 這是我們重構的地方:

public void PrintError(A obj) 
{
    PrintError(obj.getError());
}

public void PrintError(B obj) 
{
    PrintError(obj.getError());
}

//This is private, so you can only call PrintError publicly with an A or B instance
private void PrintError(string error)
{
    Console.WriteLine("Error: {0}", error);
    //maybe some more logic
}

現在,您已經具有類型安全性,您無需重復自己,也不會通過與設計語言相反的方式來使用它來“對抗語言”。

使用多個原型

當然,您可以定義多個原型,每個原型都接受一個不同的類。 編譯器將自動選擇匹配的方法簽名。 例:

public static void PrintError(ExternalClasses.A a)
{
    Console.WriteLine(a.getError());
}
public static void PrintError(ExternalClasses.B b)
{
    Console.WriteLine(b.getError());
}

使用單個原型,但進行隱式轉換

另一種方法是定義自己的類並設置隱式轉換:

public class ErrorContainer
{
    protected string _error = null;

    public string getError()
    {
        return _error;
    }

    public override string ToString()
    {
        return getError();
    }

    static public implicit operator ErrorContainer(ExternalClasses.A a)
    {
        var e = new ErrorContainer();
        e._error = a.getError();
        return e;
    }
    static public implicit operator ErrorContainer(ExternalClasses.B b)
    {
        var e = new ErrorContainer();
        e._error = b.getError();
        return e;
    }
}

然后,您可以定義PrintError接受ErrorContainer:

public static void PrintError(ErrorContainer e)
{
    Console.WriteLine(e);
}

...可讓您“通過”以下任一類型:

var a = new ExternalClasses.A();
PrintError(a);

var b = new ExternalClasses.B();
PrintError(b);

在幕后,當然, AB都將轉換為ErrorContainer

DotNetFiddle上的示例

暫無
暫無

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

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