[英]Improve Code Reuse (Python-style decorator for c#?)
我正從python轉到c#,而我想念的一件事是python風格的裝飾器。 如果我在許多功能(驗證檢查等)的頂部重復了代碼,則可以創建一個裝飾器來執行此操作。
我已經看到有一些c#裝飾器,但是看起來它們在類級別上的工作更多。 雖然我對他們有些困惑。
無論如何-您將如何改善此功能中的代碼重用/ DRY? 該功能中的所有內容都是通用的,除了標記的兩個位置。 它的回調驅動到服務器的Tcp請求,並帶有阻止多個並發請求的塊(檢查空閑狀態)。
public void MyFunction(string apples, Action<TcpRequest> onSuccess=null, Action<TcpRequest> onError=null)
{
// Throw exception if already busy with an operation
if (!state.Has(State.Idle)) { throw new OperationInProgress(); }
// Define callback action
Action<TcpRequest> callback = delegate (TcpRequest request)
{
// Add idle state back in
state.Add(State.Idle);
// Check if the request succeeded
if (request.OK)
{
/**
* Unique code here
*/
}
// Request failed. Call the onError callback if provided
else { onError?.Invoke(request); }
};
// Remove idle state
state.Remove(State.Idle);
/**
* Unique code here, that will later trigger the callback
*/
}
編輯:我並不是真的將其視為代碼審查任務,但是現在我可以看到了。 這是整個課堂,展示了狀態/變量如何相互作用。 Server類負責處理我們(客戶端)與網絡服務器之間的交互,以處理游戲登錄以及創建/加入比賽。
我沒有固定在任何特定的結構上,但是在某些時候,我想將UI按鈕連接到諸如Server.Login()
和Server.JoinMatch()
類的簡單函數,而無需產生混亂的類。
public class Server
{
#region Fields
public string playerName { get; private set; }
public string playerID { get; private set; }
public string playerToken { get; private set; }
public string currentMatchID { get; private set; }
private Patterns.State<ServerState> state = new Patterns.State<ServerState>();
#endregion
public Server()
{
state.Add(ServerState.Idle);
}
public void Login(string playerName, Action<TcpRequest> onSuccess = null, Action<TcpRequest> onError = null)
{
// Throw exception already busy with an operation
if (!state.Has(ServerState.Idle)) { throw new OperationInProgress(); }
// Define login callback action
Action<TcpRequest> loginCallback = delegate (TcpRequest request)
{
// Add idle state back in
state.Add(ServerState.Idle);
// Check if the request succeeded
if (request.OK)
{
// Store player data in class
playerName = (string)request.requestJson["player_name"];
playerID = (string)request.responseJson["player_id"];
playerToken = (string)request.responseJson["player_token"];
// Add the logged in state
state.Add(ServerState.LoggedIn);
// Call the onSuccess callback if provided
onSuccess?.Invoke(request);
}
// Login failed, call the onError callback if provided
else { onError?.Invoke(request); }
};
// Remove idle state
state.Remove(ServerState.Idle);
// Perform request
Request("login", callback: loginCallback, requestJson: new Dictionary<string, object> { { "player_name", playerName }, { "client_version", "test1" } });
}
public void CreateMatch(string matchName, Action<TcpRequest> onSuccess = null, Action<TcpRequest> onError = null)
{
// Throw exception already busy with an operation
if (!state.Has(ServerState.Idle)) { throw new OperationInProgress(); }
// Define callback action
Action<TcpRequest> callback = delegate (TcpRequest request)
{
// Add idle state back in
state.Add(ServerState.Idle);
// Check if the request succeeded
if (request.OK)
{
// Add the inLobby state
state.Add(ServerState.InLobby);
// Call the onSuccess callback if provided
onSuccess?.Invoke(request);
}
// Request failed. Call the onError callback if provided
else { onError?.Invoke(request); }
};
// Remove idle state
state.Remove(ServerState.Idle);
// Perform request
AuthenticatedRequest("match/create", callback: callback, requestJson: new Dictionary<string, object> { { "match_name", matchName } });
}
public void JoinMatch(string matchID, Action<TcpRequest> onSuccess = null, Action<TcpRequest> onError = null)
{
// Throw exception already busy with an operation
if (!state.Has(ServerState.Idle)) { throw new OperationInProgress(); }
// Define callback action
Action<TcpRequest> callback = delegate (TcpRequest request)
{
// Add idle state back in
state.Add(ServerState.Idle);
// Check if the request succeeded
if (request.OK)
{
// Add the inLobby state
state.Add(ServerState.InLobby);
// Set currentMatchID in class
currentMatchID = (string)request.responseJson["match_id"];
// Call the onSuccess callback if provided
onSuccess?.Invoke(request);
}
// Request failed. Call the onError callback if provided
else { onError?.Invoke(request); }
};
// Perform request
AuthenticatedRequest("match/join", callback: callback, requestJson: new Dictionary<string, object> { { "match_id", matchID } });
}
private void Request(string resource, Action<TcpRequest> callback = null, Dictionary<string, object> requestJson = null)
{
// Start async request, invoke callback when done
}
private void AuthenticatedRequest(string resource, Action<TcpRequest> callback = null, Dictionary<string, object> requestJson = null)
{
// Add login auth data into the requestJson dict or throw exception if we aren't logged in
// Call Request()
}
}
取決於是否必須始終成對使用兩個唯一的代碼,否則我會選擇其他方法。
如果要強制使用“成對用法”,則可以使用抽象類:
public abstract class MyClass
{
public void MyFunction(string apples, Action<TcpRequest> onSuccess=null, Action<TcpRequest> onError=null)
{
// Throw exception if already busy with an operation
if (!state.Has(State.Idle)) { throw new OperationInProgress(); }
// Define callback action
Action<TcpRequest> callback = delegate (TcpRequest request)
{
// Add idle state back in
state.Add(State.Idle);
// Check if the request succeeded
if (request.OK)
{
SomethingUnique1();
}
// Request failed. Call the onError callback if provided
else { onError?.Invoke(request); }
};
// Remove idle state
state.Remove(State.Idle);
SomethingUnique2(callback);
}
protected abstract void SomethingUnique1();
protected abstract void SomethingUnique2(Action<TcpRequest> callback);
}
然后根據需要實現多個子類:
public sealed class MyClassVariant1 : MyClass
{
protected override SomethingUnique1() { /*...*/ }
protected override SomethingUnique2(Action<TcpRequest> callback) { /*...*/ }
}
public sealed class MyClassVariant2 : MyClass
{
protected override SomethingUnique1() { /*...*/ }
protected override SomethingUnique2(Action<TcpRequest> callback) { /*...*/ }
}
如果由於一個“唯一的東西1”可能與許多“唯一的東西2”同時使用而不能強制使用配對,那么我會鼓勵采用一種裝飾性的方法:
public sealed class MyClass
{
private readonly Action somethingUnique1;
private readonly Action<TcpRequest> somethingUnique2;
public MyClass(Action somethingUnique1, Action<TcpRequest> somethingUnique2)
{
this.somethingUnique1 = somethinUnique1;
this.somethinUnique2 = somethingUnique2;
}
public void MyFunction(string apples, Action<TcpRequest> onSuccess=null, Action<TcpRequest> onError=null)
{
// Throw exception if already busy with an operation
if (!state.Has(State.Idle)) { throw new OperationInProgress(); }
// Define callback action
Action<TcpRequest> callback = delegate (TcpRequest request)
{
// Add idle state back in
state.Add(State.Idle);
// Check if the request succeeded
if (request.OK)
{
somethingUnique1();
}
// Request failed. Call the onError callback if provided
else { onError?.Invoke(request); }
};
// Remove idle state
state.Remove(State.Idle);
somethingUnique2(callback);
}
}
接着
var variant1 = new MyClass(() => { /* ... */ }, (TcpRequest r) => { /* ... */ });
var variant2 = new MyClass(() => { /* ... */ }, (TcpRequest r) => { /* ... */ });
在這里,該方法更具可組合性,因此限制較少。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.