What's the difference between a partial method and a partial class?

What's the difference between a partial method and a partial class?

Rate This
  • Comments 33

Like "fixed" and "into", "partial" is also used in two confusingly similar-yet-different ways in C#.

The purpose of a partial class is to allow you to textually break up a class declaration into multiple parts, usually parts found in separate files. The motivation for this feature was machine-generated code that is to be extended by the user by adding to it directly. When you draw a form in the forms designer, the designer generates a class for you representing that form. You can then further customize that class by adding more code to it. If you can edit the machine-generated code then any number of problems arise. What if it is re-generated? What if the machine is using the code itself as a persisted state for design-time information about the class, and your edit messes up the machine's parser? It's much better to simply put the machine-generated half in its own file, generate a comment that says "can't touch this", and put the user code in its own location.

There are other uses of partial classes that do not involve machine-generated code but they are relatively rare. Some cases where I see partial classes used are:

  • If a class is really large and implements a bunch of interfaces, sometimes one interface implementation per file makes sense. More often though this is a bad code smell which indicates a class that is trying to do too much; it might be better to split this thing up into multiple classes.
  • It's somtimes nice to put nested classes in their own files; making the containing class partial is the only good way to do that.
  • And so on.

Partial methods are a subtly different story. Like partial classes, partial methods are about combining multiple declarations of the same method to make machine-generated code scenarios better. But though the high-level purpose of the feature is the same, the details are rather different.

The way a partial method works is there are two declarations, the "latent" declaration and the "actual" declaration. The latent declaration does not have a body, like it was an abstract method. The actual declaration does. The latent declaration goes in the machine-generated side of a partial class, the actual declaration goes in the human-authored side. If there is an actual declaration, then the latent declaration is completely ignored. But if there is no actual declaration then all calls to the method are removed, just as it the method were compiled with the conditional attribute! And in fact, the latent declaration is also logically removed when we spit out the metadata for the generated class; it's as if it never was.

The reason for this behaviour is because we wanted to enable this scenario:

 // Machine generated code:
partial class MyFoo
{
  void ButtonClickEventHandler(/*whatever*/)
  {
      // call user code to see if they want to do anything at this time
      OnBeforeButtonClick(whatever);
      blah blah blah
      // call user code again
      OnAfterButtonClick(whatever);
  }
  partial void OnBeforeButtonClick(/*whatever*/); 
  partial void OnAfterButtonClick(/*whatever*/);
...

The user is going to be customizing the partial class; by putting in partial methods, the machine-generated side can create simple customization points all over the show that the user can then implement. But consider the down sides of this in a world without partial methods. The user is forced to implement empty methods. If they do not, they get errors. There are potentially hundreds of these empty methods to implement, which is vexing. And each of those methods generates a non-trivial amount of metadata, making the final binary larger than it needs to be. Disk space is cheap but network latency has replaced disk space as the factor that discourages large assemblies. If we can eliminate that metadata burden, that would be great.

Partial methods fit the bill. The user can provide actual implementations for as many methods as they choose, and now this becomes a "pay to play" model; you get as much implementation expense as the number of actual methods you implement.

The name of the feature during the design process was "latent and actual methods"; we strongly considered adding new keywords "latent" and "actual". But since the feature only makes sense in partial class scenarios, we decided to re-use the existing contextual keyword "partial" and renamed the feature. Hopefully the consonance between the two uses of "partial" helps more than the subtle differences hurt.

SUPER EXTRA BONUS: Yet more partiality

We considered adding a third kind of "partiality" to C# 4; this feature made it through the design phase but got cut before implementation. (If there is high demand, we'll consider adding it to hypothetical future versions of C#.) 

Sometimes you're in a machine-generated code scenario like this:

// Machine generated
partial class C
{
  int blah;
...

and then in the user-generated side of things, you want to do something like:

// User generated
partial class C : ISerializable
{

And oh heck, I need to put the NotSerialized attribute on blah, but I cannot edit the text of blah because when it gets re-generated, that will be lost.

The idea of this new kind of partiality is to re-state the declaration of a member -- a field, method, nested type, whatever -- with metadata attributes. It's like a latent/actual method but in reverse; the "actual" thing is in the machine-generated side, the "latent" thing in the user-generated side is just there to add metadata:

[NotSerialized] partial int blah; // not actually a declaration of a field

I like this feature but during the design process I pushed back hard on using the "partial" keyword to have a third meaning subtly different from the other two. Adding this confusion once seemed justifiable, but twice? That's pushing it. We therefore settled on adding another contextual keyword:

[NotSerialized] existing int blah; // not actually a declaration of a field

Decorating a declaration with "existing" would mean "this is not a real declaration, this is a mention of an existing declaration; please verify that such a declaration exists somewhere else in this partial class, and add this metadata to that member".

Like I said, this handy feature got cut because of resource constraints. If you have really awesome scenarios that this would make easier, I'd love to hear about them; obviously I cannot make any promises about possible future features of unannounced, entirely hypothetical products. But real user scenarios are a highly motivating factor in getting budget for features.

 

  • A scenario that immediately comes to mind for this feature is to stick attributes onto fields of classes generated by LINQ to SQL or Entity Framework designers. I see at least one question about how to do it on Stack Overflow every week, and so far the stock reply is "you have to forget about designer and hand-code your classes", which obviously isn't perfect.

    Indeed, I believe it was the entity framework team that first requested this feature of us. -- Eric

  • The last case seems as if it could be handled through existing language features.

    A class level NonSerialized attribute with a parameter list of which fields to skip could handle the problem without making a special language feature.

  • It's funny you mentioned partial methods. I just learned about them a couple weeks ago, and ran into a need for them last week. And now you have a whole article about them!

    Is there any way that you could make it so that only one part of the partial class has to name the base class? That way the code generator could always generate generic classes and the person adding implementation could decide what class to inherit from.

    As it is now, you have to figure out some way to tell the code generator what each class is supposed to inherit from. Or edit the generated code each time.

  • Seconding Gabe's feature request. Better yet would be to allow different base classes to be named as long as one of them is a derived class of all the others. So the generated side can say "I inherit from System.Web.Forms.UserControl" and the human-generated side can say "Actually I inherit from FooCorpCustomControl which inherits from UserControl" and the resulting class ends up deriving from FooCorpCustomControl.

  • Isn't what Gabe is asking for the existing behavior?

    (sample from MDSN):

    partial class Earth : Planet, IRotate { }

    partial class Earth : IRevolve { }

    They are equivalent to the following declarations:

    class Earth : Planet, IRotate, IRevolve { }

  • I've cursed the inability to add attributes to generated members numerous times. Linq to SQL .designer.cs files and xsd.exe-generated XmlSerializer declarations are our most frequent needs. We have some special sauce we put in our DataContext base classes where we poke around in metadata, and we had to ditch doing it with custom attributes (we re-gen the designer files way too frequently). Orcas B1 had the ability to add arbitrary attributes in the DBML designer, but that got replaced with "Serialization Mode" by RTM. The XmlSerializer story has always been lame for this.

  • It has always been odd to me that partial methods make this distinction between the "latent" declaration and the "actual" declaration; it would have been much more natural to me to treat them just like partial classes, where any number of declarations are allowed as long as the declarations don't conflict (and obviously having more than one implementation would be a conflict). This would also have made the distinction between partial classes and partial methods less severe, and lessen the confusion around the overloading of the partial keyword. I can also imagine that it would enable some edge cases where the same class is partially generated by different generators.

    "Partial members" (or whatever it would be called) could work the same way: you can re-define a partial member as many times as you want as long as the definitions don't conflict.

  • oh it is a shame that the c# team has so few resources. if it took you 100 million $ to increase productivity by 10% (easy) it would be amortized for microsofts internal c# usage in one single year. it is an outrageous economic mistake. same for c++. same for the .net runtime wich could be optimized so that .net starts up as fast as c++ so it can be used to develop windows (thats easy too: just write an il -> native binary compiler and not release it to the public).

  • > Thats easy too: just write an il -> native binary compiler

    http://msdn.microsoft.com/en-us/library/6t9t5wcf.aspx

  • I agree with David Nelson. I understand the "partial" keyword as "there's some more about that elsewhere", so using the "partial" keyword to add attributes to generated fields seems ok to me... I would be more confused with an "existing" keyword. And you could use "partial" for pretty much everything (properties for exemple to add a "get" or a "set", abstract classes, interfaces...).

  • I don't see any value in existing keyword except to hide a minor weakness in the code generator. I think we need better code generators instead of a language feature in this particular case. After all, attributes are just metadata not code, they can be added by any code generator (for example, the class designer does it very well).

  • Yet more partiality....

    Please let me know how to effectly make my "DEMAND" for the ability to use partial methods (or something equivilant) for decorating items with additional attributes have sufficient weight that it will be added ASAP....

    ps: Hopefully it doesn't involve anything illegal, immoral or fattening (actually fattening would be OK!)

  • I noticed a 'creative' new use of partial classes recently.   The Bling framework is a very slick DSL-in-C#, heavily using expression trees to manage complex layout/animation/shaders in WPF applications.

    It uses a curious code organization with many of it's core classes marked as partial and spread across several files by area of concern.  For example, there's a Value<T> class that's spread between DSL.cs, DataBinding.cs and Physics.cs.   In many senses the code added in DataBinding is build on what's in DSL, and similarly the Physics code depends on previous two.

    The resulting framework is very very cool, but I'm undecided on the merits of this use of partial classes.

    Does anyone else write code organized this way?

  • Your sample code "should" be OnButtonClicking() and OnButtonClicked() to comply with the code analysis (FxCop) naming guidelines.

  • I believe the last feature you describe is achievable through "buddy classes"...?

    http://blog.pagedesigners.co.nz/archive/2009/08/06/asp.net-mvc-2-ndash-buddy-classes-for-your-models.aspx

Page 1 of 3 (33 items) 123