C#: Partial Classes versus Regions

Intro

In .NET, we can stop relying on code regions within a class and instead use partial classes and file nesting to isolate code. An example of nested classes is the following: NestedFiles Regions are sections of collapsible code within a class. A “Helpers” region is shown below.

        #region Helpers
        private void OnLoadContent(object obj)
        {
            var repository = obj as IRepository;

            var dbContent1 = repository.Get(1);
            var dbContent2 = repository.Get(2);
            var dbContent3 = repository.Get(3);
            var dbContent4 = repository.Get(4);

            Content1 = dbContent1 != null ? dbContent1 : new Content() { Id = 1, Value = "Copy & paste me (1)" };
        }

        private void OnContentRequested(object obj)
        {
            var text = obj as string;
            var content = GetContent(obj);
            _messagebus.Publish(Messages.REQUEST_CONTENT_RESPONSE, content);
        }
        #endregion

The following is an extended example of how regions can be used for properties and private methods:

public partial class ViewModel : ViewModelBase
    {
        public ViewModel()
        {
            _messagebus.Subscribe(Messages.REQUEST_SET_CLIPBOARD, obj => CopyMade = true);
            _messagebus.Subscribe(Messages.CONTENT_SELECTED, OnContentSelected);
            _messagebus.Subscribe(Messages.REQUEST_LOAD_CONTENT, OnLoadContent);
            _messagebus.Subscribe(Messages.REQUEST_CONTENT, OnContentRequested);
        }

        #region Properties
        Content _content1 = null;
        public Content Content1
        {
            get
            {
                return _content1;
            }
            set
            {
                if (_content1 != value)
                {
                    _content1 = value;
                    OnPropertyChanged();
                }
            }
        }

        

        bool _copyMade = false;
        public bool CopyMade
        {
            get
            {
                return _copyMade;
            }
            set
            {
                if (_copyMade != value)
                {
                    _copyMade = value;
                    OnPropertyChanged();
                }
            }
        }

        Content _selectedContent = null;
        public Content SelectedContent
        {
            get
            {
                return _selectedContent;
            }
            set
            {
                if (_selectedContent != value)
                {
                    _selectedContent = value;
                    OnPropertyChanged();
                }
            }
        }
        #endregion

        #region Helpers
        private void OnLoadContent(object obj)
        {
            var repository = obj as IRepository;
            var dbContent1 = repository.Get(1);

            Content1 = dbContent1 != null ? dbContent1 : new Content() { Id = 1, Value = "Copy & paste me (1)" };
        }

        private void OnContentRequested(object obj)
        {
            var text = obj as string;
            var content = GetContent(obj);
            _messagebus.Publish(Messages.REQUEST_CONTENT_RESPONSE, content);
        }
        #endregion
    }

As you can see, the class definition is becomes obscured when all sections are expanded. As a result, we may find ourselves scrolling up and down class definitions to maintain a class implementation. Having that type of user experience can be burdensome. There should be an alternative method for segregating sections of code.

Partial Classes

Partial classes enables multiple files to share a class definition. An example of a common partial class is a XAML file. MainWindow.xaml and MainWindow.xaml.cs is often observed in WPF projects. Partial classes can also be used as an alternative to regions. For example, we can take our past view-model class and change its state to a partial class. Example:

  • ViewModel.cs
  • ViewModel.support.cs

ViewModel.cs can expose the public properties of the class. ViewModel.support.cs can harbor member variables and private methods for the view-model. Example: project_nested_files In order for partial classes to be supported, the following partial class declaration must be made:

public partial class ViewModel

Then we can remove the private members and methods from the view-model class and put it in a supporting partial class. Example:

    public partial class ViewModel : ViewModelBase
    {
        public ViewModel()
        {
            _messagebus.Subscribe(Messages.REQUEST_SET_CLIPBOARD, obj => CopyMade = true);
            _messagebus.Subscribe(Messages.CONTENT_SELECTED, OnContentSelected);
            _messagebus.Subscribe(Messages.REQUEST_LOAD_CONTENT, OnLoadContent);
            _messagebus.Subscribe(Messages.REQUEST_CONTENT, OnContentRequested);
        }

        Content _content1 = null;
        public Content Content1
        {
            get
            {
                return _content1;
            }
            set
            {
                if (_content1 != value)
                {
                    _content1 = value;
                    OnPropertyChanged();
                }
            }
        }

        

        bool _copyMade = false;
        public bool CopyMade
        {
            get
            {
                return _copyMade;
            }
            set
            {
                if (_copyMade != value)
                {
                    _copyMade = value;
                    OnPropertyChanged();
                }
            }
        }

        Content _selectedContent = null;
        public Content SelectedContent
        {
            get
            {
                return _selectedContent;
            }
            set
            {
                if (_selectedContent != value)
                {
                    _selectedContent = value;
                    OnPropertyChanged();
                }
            }
        }
    }

The supporting partial class that defines members and private methods can be the following:

public partial class ViewModel

{

MessageBus _messagebus = MessageBus.Instance;

public void OnContentSelected(object obj)

{

var content = GetContent(obj);

SelectedContent = content;

}

private void OnLoadContent(object obj)

{

var repository = obj as IRepository;

var dbContent1 = repository.Get(1);

Content1 = dbContent1 != null ? dbContent1 : new Content() { Id = 1, Value = "Copy & paste me (1)" };

}

private void OnContentRequested(object obj)

{

var text = obj as string;

var content = GetContent(obj);

_messagebus.Publish(Messages.REQUEST_CONTENT_RESPONSE, content);

}

private Content GetContent(object obj)

{

var text = obj as string;

var contentList = new List<Content>() { Content1 };

var content = contentList.Where(c => c.Value == text).FirstOrDefault();

return content;

}

}

Note how we have two class declarations for the same class. This is only possible using the “partial” declaration.

Nesting files

We can consolidate partial classes by nesting them under the exposed interface of the class: NestedFiles To do this perform the following:

  1. In Visual Studio, navigate to Tools | Extensions and Updates
  2. Select the Online tab
  3. Search for “File Nesting”
  4. Install the extension

Extentions_NestedFiles After the extension is installed, within Solution Explorer, right-click a class file and select: File Nesting | Nest Item. You can then select a parent file to nest the selected file under.

Conclusion

In conclusion, within .NET, I explained how we could stop relying on code regions within a class and instead use partial classes and file nesting to isolate code.

NOTE:

Scott Nimrod is fascinated with Software Craftsmanship. He loves responding to feedback and encourages people to share his articles. He can be reached at scott.nimrod @ bizmonger.net

Advertisements
3 comments
  1. Very interesting. I never knew about the nesting file extension.

    My VMs rarely have #regions because so much setup is taken care by in-house custom framework. It basically abstracts all the wiring for observables, etc.

    I have #regions at my service (API) code though. Sometimes I have all of these helper methods which are only used within that class. Instead of creating a new HelperXYZ.cs file, I opt to push them down on the .cs file. Sometimes I wrap them inside a #region.

    TL;DR
    The nestinf file extension is cool and a nifty trick. My services (API) could probably benefit from this.

    How does this work when debugging?

    • No change in behavior of the debugger.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: