title: Improve Code Reuse (Python-style decorator for c#?)
body: <p>I'm moving from python to c#, and one of the things I miss is python-style decorators. If I had repeated code at the top of a load of functions (validation checking etc), I could create a decorator to do it. </p>
  
  <p>I've seen that there are c# decorators of a sort, but they look like they work more on the class level. Although I am a bit confused by them.</p>
  
  <p>Regardless - how would you go about improving code re-use/DRY in this function? All the stuff in the function is common, except the two places marked. Its callback driven Tcp requests to a server, with a block to stop multiple concurrent requests (check for Idle state).</p>
  
  <pre class="lang-cs prettyprint-override"><code>    public void MyFunction(string apples, Action&lt;TcpRequest&gt; onSuccess=null, Action&lt;TcpRequest&gt; onError=null)
      {
          // Throw exception if already busy with an operation
          if (!state.Has(State.Idle)) { throw new OperationInProgress(); }
  
          // Define callback action
          Action&lt;TcpRequest&gt; 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
           */
      }
  </code></pre>
  
  <p>EDIT: I wasn't really thinking of this as a code review task, but now I can see it is. Here is the whole class, showing how the states/vars interact. The Server class handles interactions between us (the client) and a webserver to handle game login, and create/join match.</p>
  
  <p>I'm not fixed on any particular structure, but at some point I want to connect UI buttons to simple functions like <code>Server.Login()</code> and <code>Server.JoinMatch()</code>, without needing to spawn messy classes.</p>
  
  <pre><code>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&lt;ServerState&gt; state = new Patterns.State&lt;ServerState&gt;();
      #endregion
  
      public Server()
      {
          state.Add(ServerState.Idle);
      }
  
      public void Login(string playerName, Action&lt;TcpRequest&gt; onSuccess = null, Action&lt;TcpRequest&gt; onError = null)
      {
          // Throw exception already busy with an operation
          if (!state.Has(ServerState.Idle)) { throw new OperationInProgress(); }
  
          // Define login callback action
          Action&lt;TcpRequest&gt; 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&lt;string, object&gt; { { "player_name", playerName }, { "client_version", "test1" } });
      }
  
      public void CreateMatch(string matchName, Action&lt;TcpRequest&gt; onSuccess = null, Action&lt;TcpRequest&gt; onError = null)
      {
          // Throw exception already busy with an operation
          if (!state.Has(ServerState.Idle)) { throw new OperationInProgress(); }
  
          // Define callback action
          Action&lt;TcpRequest&gt; 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&lt;string, object&gt; { { "match_name", matchName } });
      }
  
      public void JoinMatch(string matchID, Action&lt;TcpRequest&gt; onSuccess = null, Action&lt;TcpRequest&gt; onError = null)
      {
          // Throw exception already busy with an operation
          if (!state.Has(ServerState.Idle)) { throw new OperationInProgress(); }
  
          // Define callback action
          Action&lt;TcpRequest&gt; 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&lt;string, object&gt; { { "match_id", matchID } });
      }
  
      private void Request(string resource, Action&lt;TcpRequest&gt; callback = null, Dictionary&lt;string, object&gt; requestJson = null)
      {
          // Start async request, invoke callback when done
      }
  
      private void AuthenticatedRequest(string resource, Action&lt;TcpRequest&gt; callback = null, Dictionary&lt;string, object&gt; requestJson = null)
      {
          // Add login auth data into the requestJson dict or throw exception if we aren't logged in
          // Call Request()
      }
  }
  </code></pre>