Saturday, February 29, 2020

Organize Your Projects With Partial Classes

I was recently asked if I had any type of procedure or process that I follow for creating Classes. I responded, "No, I don’t have anything concrete for doing that. Sometimes whatever you’re trying to accomplish can dictate how you will handle creating classes".

But here's one tip that I find can often be useful and that is, as the title of this post indicates, using partial classes for project organization. It can also be useful when you have a few different team members that need to work on different parts of the class. Let me explain ...

Let's say you have an application that processes various types of messages that it receives. This is what MyMessage class might look like:

public class MyMessage
{
public string MessageType { get; set; }
public string MessageData { get; set; }
public DateTime CreatedDatetime { get; set; }
public string ReceivedFrom { get; set; }
public string SendTo { get; set; }
}

Now, let's say that you have three categories of messages: Incidents, Requests, Resources. You might organize this by having four partial class files. These four files could be named MessageProcessor.cs, MessageIncidentProcessor.cs, MessageResourceProcessor.cs and MessageRequestProcessor.cs. Note that all these files start with the word "Message" ... this effectively groups them all together in your project making it obvious that they belong together and making them easy to find in your project.

One could also use project folders for organizing similar functionality, but I often find that it's easier to find what you're looking for by grouping by name of file and not "hiding" files in folders. Maybe that's just me.  ;0) It probably also depends on the size of your project (if you have a lot of files in your project, perhaps folder organization is better). However, that is *NOT* the topic of this blog post! It's about partial classes!  =0)

As you may have guessed by now, the partial class will be called MessageProcessor and the MessageProcessor.cs file will contain all the variables and methods that are common between the various MessageTypes. Any method that is common to at least two MessageTypes belongs here. The main functionality of the code in the MessageProcessor.cs file is to receive the message, and then call the appropriate method to process it (which will be methods in the other .cs files).

OK, now for the code:

First, the "controlling" MessageProcessor.cs partial class file.

public partial class MessageProcessor
{
// Note that the constructor is only in this "main" class file
public MessageProcessor()
{
// initialize stuff here, probably having to do with setting up
// for receiving messages, and whatever else all three message types
// have in common for
}
// Next, we'll have all methods that are common to all types of Messages
// The first being processing the incoming message and calling the appropriate methods
public bool ProcessMessage(MyMessage message)
{
bool IsOK = true;
switch (message.MessageType)
{
// Incidents
case "NewIncident":
IsOK = this.ProcessNewIncident(message);
break;
case "UpdateIncident":
IsOK = this.ProcessIncidentUpdate(message);
break;
case "CloseIncident":
IsOK = this.ProcessIncidentClose(message);
break;
// Resources
case "NewResource":
IsOK = this.ProcessNewResource(message);
break;
case "AssignResource":
IsOK = this.ProcessResourceAssignment(message);
break;
case "UpdateResource":
IsOK = this.ProcessResourceUpdate(message);
break;
// Requests
case "RequestForTransfer":
IsOK = this.ProcessTransferRequest(message);
break;
default:
// some default behavior or
// log error or ignore or whatever
break;
}
return IsOK;
}
// Add additional methods that are common across all MessageTypes
}

Name the next file MessageIncidentProcessor.cs

public partial class MessageProcessor
{
protected bool ProcessNewIncident(MyMessage message)
{
bool IsOK = true;
// Necessary code to process, setting IsOK as needed
return IsOK;
}
protected bool ProcessIncidentUpdate(MyMessage message)
{
bool IsOK = true;
// Necessary code to process, setting IsOK as needed
return IsOK;
}
protected bool ProcessIncidentClose(MyMessage message)
{
bool IsOK = true;
// Necessary code to process, setting IsOK as needed
return IsOK;
}
// Add additional methods that are only used for Incidents
}

The next file is called MessageResourceProcessor.cs

public partial class MessageProcessor
{
protected bool ProcessNewResource(MyMessage message)
{
bool IsOK = true;
// Necessary code to process, setting IsOK as needed
return IsOK;
}
protected bool ProcessResourceAssignment(MyMessage message)
{
bool IsOK = true;
// Necessary code to process, setting IsOK as needed
return IsOK;
}
protected bool ProcessResourceUpdate(MyMessage message)
{
bool IsOK = true;
// Necessary code to process, setting IsOK as needed
return IsOK;
}
// Add additional methods that are only used for Resources
}

And, lastly, call this file MessageRequestProcessor.cs

public partial class MessageProcessor
{
protected bool ProcessTransferRequest(MyMessage message)
{
bool IsOK = true;
// Necessary code to process, setting IsOK as needed
return IsOK;
}
// Add additional methods that are only used for Requests
}

Well, now let's say that the Requests need an additional constructor. Let's change the MessageRequestProcessor.cs file to look like this:

public partial class MessageProcessor
{
private bool SendResponse = false;

// An additional constructor needed for Requests
public MessageProcessor(bool sendResponse) : base()
{
this.SendResponse = sendResponse;
}
protected bool ProcessTransferRequest(MyMessage message)
{
bool IsOK = true;
// Necessary code to process, setting IsOK as needed
if (this.SendResponse)
{
// code to send the response
}
return IsOK;
}
// Add additional methods that are only used for Requests
}

Now, how does this structure help co-worker cooperation? If I'm working on Incidents and another developer on my Team is working on Resources, we don't have to worry about stepping on each other's toes and making sure that we are careful with TFS check-ins and check-outs. TFS normally makes this fairly painless, but not always. Sometimes the process of merging code that I'm checking in with code that another developer has checked in, does not go easily. I'd rather avoid it.  This way, my co-worker checks out the MessageResourceProcessor.cs file and I check out the MessageIncidentProcessor.cs file ... and we're both happy!!  =0)

I hope this post has given you some good ideas ... Happy Coding!  =0)

2 comments:

  1. Very nice, very clear explanation.
    Thanks
    Vojislav

    ReplyDelete
    Replies
    1. Thanks, Vojislav … glad you liked it! =0)

      Delete