簡體   English   中英

c#委托和抽象類

[英]c# delegate and abstract class

我目前在2個抽象類中有2個具體方法。 一個類包含當前方法,而另一個類包含遺留方法。 例如

// Class #1
public abstract class ClassCurrent<T> : BaseClass<T> where T : BaseNode, new()
{
    public List<T> GetAllRootNodes(int i)
    {
      //some code
    }
}

// Class #2
public abstract class MyClassLegacy<T> : BaseClass<T> where T : BaseNode, new()
{
    public List<T> GetAllLeafNodes(int j)
    {
      //some code
    }
}

我希望相應的方法在應用程序的相對場景中運行。 我打算寫一個代表來處理這件事。 我的想法是,我可以調用委托並在其中編寫邏輯來處理調用哪個方法,具體取決於調用它的類/項目(至少我認為委托的用途以及如何使用它們)。

但是,我對該主題有一些疑問(經過一些谷歌搜索):

1)是否可以讓代理知道位於不同類中的2個(或更多)方法? 2)是否可以使一個委托產生抽象類(如上面的代碼)? (我的猜測是否定的,因為委托創建了傳入類的具體實現)3)我試着為上面的代碼編寫一個委托。 但我在技術上受到挑戰:

    public delegate List<BaseNode> GetAllNodesDelegate(int k);
    GetAllNodesDelegate del = new GetAllNodesDelegate(ClassCurrent<BaseNode>.GetAllRootNodes);

我收到以下錯誤:

An object reference is required for the non-static field, method, property ClassCurrent<BaseNode>.GetAllRootNodes(int)

我可能誤解了一些東西......但如果我必須在調用類中手動聲明一個委托,並且如上所述手動傳遞函數,那么我開始質疑委托是否是處理我的問題的好方法。

謝謝。

您嘗試使用委托的方式(使用new構造它們,聲明一個命名的委托類型)表明您正在使用C#1.如果您實際使用的是C#3,那么它就容易多了。

首先,你的代表類型:

public delegate List<BaseNode> GetAllNodesDelegate(int k);

已經存在。 只是:

Func<int, List<BaseNode>>

所以你不需要聲明自己的版本。

其次,您應該將委托視為只有一個方法的接口,並且您可以動態“實現”它,而無需編寫命名類。 只需編寫一個lambda,或直接指定一個方法名稱。

Func<int, List<BaseNode>> getNodesFromInt;

// just assign a compatible method directly
getNodesFromInt = DoSomethingWithArgAndReturnList;

// or bind extra arguments to an incompatible method:
getNodesFromInt = arg => MakeList(arg, "anotherArgument");

// or write the whole thing specially:
getNodesFromInt = arg =>
    {
        var result = new List<BaseNode>();
        result.Add(new BaseNode());
        return result;
    };

lambda的形式(arguments) => { body; } (arguments) => { body; } 參數以逗號分隔。 如果只有一個,則可以省略括號。 如果它不帶參數,則放一對空括號:( () 如果正文只有一個語句,則可以省略大括號。 如果它只是一個表達式,則可以省略大括號和return關鍵字。 在正文中,您幾乎可以參考封閉范圍內的任何變量和方法(除了ref / out參數到封閉方法)。

幾乎從來沒有必要使用new來創建委托實例。 並且很少需要聲明自定義委托類型。 對於返回值的委托使用Func對返回void委托使用Action

每當你需要傳遞的東西就像一個帶有一個方法的對象(無論是接口還是類),然后使用委托,你就能避免很多混亂。

特別是,避免使用一種方法定義接口。 它只是意味着不是能夠編寫lambda來實現該方法,而是必須為每個不同的實現聲明一個單獨的命名類,其模式如下:

class Impl : IOneMethod
{
    // a bunch of fields

    public Impl(a bunch of parameters)
    {
        // assign all the parameters to their fields
    }

    public void TheOneMethod()
    {
        // make use of the fields
    }
}

lambda有效地為您完成所有這些工作,從您的代碼中消除了這些機械模式。 你只是說:

() => /* same code as in TheOneMethod */

它還具有可以更新封閉范圍中的變量的優點,因為您可以直接引用它們(而不是使用復制到類的字段中的值)。 如果您不想修改值,有時這可能是一個缺點。

根據某些條件,您可以使用不同方法的引用初始化委托。

關於你的問題:
1)我不確定你在“知道”下的意思。 您可以將任何方法傳遞給委托,因此如果您可以編寫“知道”某些其他方法的方法,那么您可以執行類似的委托。
2)同樣,可以從任何可以執行的方法創建委托。 例如,如果你有類型的初始化局部變量ClassCurrent<T>可以創建委托類型的任何實例方法ClassCurrent<T>
3)Delegate只能調用實際可以調用的方法。 我的意思是你不能調用ClassCurrent.GetAllRootNodes因為GetAllRootNodes不是靜態方法,所以你需要一個ClassCurrent實例來調用它。

委托可以留在任何可以訪問ClassCurrentMyClassLegacy

例如,你可以創建像:

class SomeActionAccessor<T>
{
    // Declare delegate and fied of delegate type.
    public delegate T GetAllNodesDelegate(int i);

    private GetAllNodesDelegate getAllNodesDlg;

    // Initilaize delegate field somehow, e.g. in constructor.
    public SomeActionAccessor(GetAllNodesDelegate getAllNodesDlg)
    {
        this.getAllNodesDlg = getAllNodesDlg;
    }

    // Implement the method that calls the delegate.
    public T GetAllNodes(int i)
    {
        return this.getAllNodesDlg(i);
    }
}

委托可以包裝靜態和實例方法。 唯一的區別是,對於使用實例方法的創建委托,您需要擁有該方法的類的實例。

ClassCurrentMyClassLegacy實現一個接口INodeFetcher

public interface INodeFetcher<T> { 
    List<T> GetNodes(int k);
} 

對於ClassCurrent致電GetAllRootNodes從接口的實現和方法MyLegacyClassGetAllLeaveNodes方法。

你為什么要代表這個? 聽起來太復雜了。 我只想在一個新類中創建一個方法,當你需要調用方法時,你可以實現該方法。 可以給這個類提供一些上下文信息以幫助它決定。 然后我將在新方法中實現邏輯,該方法將決定是調用當前方法還是遺留方法。

像這樣的東西:

public class CurrentOrLegacySelector<T>
{

  public CurrentOrLegacySelector(some type that describe context)
  {   
     // .. do something with the context. 
     // The context could be a boolean or something more fancy.
  }

  public List<T> GetNodes(int argument) 
  {
    // Return the result of either current or
    // legacy method based on context information
  }
}

這將為您提供易於閱讀和理解的方法的干凈包裝。

作為Rune Grimstad建議的主題的變體,我認為你可以使用戰略模式(例如
C#中GOF策略模式簡介

如果您無法更改LegacyClass(因此可能無法輕松使用Cornelius建議的“接口方法”)並且您正在使用依賴注入(DI; 依賴注入 ),這將特別有趣。 DI(也許)會讓你在正確的地方注入正確的實施(具體的策略)。

戰略:

public interface INodeFetcher<T> { 
    List<T> GetNodes(int k);
}

具體策略:

public class CurrentSelector<T> : INodeFetcher<T>
{
    public List<T> GetNodes(int argument) 
    {
    // Return the result "current" method
    }
}

public class LegacySelector<T> : INodeFetcher<T>
{
    public List<T> GetNodes(int argument) 
    {
    // Return the result "legacy" method
    }
}

- >注入/實例化正確的具體策略。

問候

暫無
暫無

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

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