我正在从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()
}
}
答案 0 :(得分:1)
取决于这两个唯一的代码,必须始终成对使用,否则我会选择其他方法。
如果要强制使用“配对用法”,则可以使用抽象类:
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) => { /* ... */ });
这里的方法更容易组合,因此限制更少。