![](/img/trans.png)
[英]How to add abstract class with generic as argument of delegate in 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
實例來調用它。
委托可以留在任何可以訪問ClassCurrent
和MyClassLegacy
。
例如,你可以創建像:
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);
}
}
委托可以包裝靜態和實例方法。 唯一的區別是,對於使用實例方法的創建委托,您需要擁有該方法的類的實例。
讓ClassCurrent
和MyClassLegacy
實現一個接口INodeFetcher
:
public interface INodeFetcher<T> {
List<T> GetNodes(int k);
}
對於ClassCurrent
致電GetAllRootNodes
從接口的實現和方法MyLegacyClass
的GetAllLeaveNodes
方法。
你為什么要代表這個? 聽起來太復雜了。 我只想在一個新類中創建一個方法,當你需要調用方法時,你可以實現該方法。 可以給這個類提供一些上下文信息以幫助它決定。 然后我將在新方法中實現邏輯,該方法將決定是調用當前方法還是遺留方法。
像這樣的東西:
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.