Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why cant partial methods be public if the implementation is in the same assembly?

According to MSDN Documentation for partial classes :

Partial methods are implicitly private

So you can have this

// Definition in file1.cs
partial void Method1();

// Implementation in file2.cs
partial void Method1()
{
  // method body
}

But you can't have this

// Definition in file1.cs
public partial void Method1();

// Implementation in file2.cs
public partial void Method1()
{
  // method body
}

But why is this? Is there some reason the compiler can't handle public partial methods?

like image 284
Simon Avatar asked Jan 08 '10 00:01

Simon


People also ask

What will happen if there is an implementation of partial method without defining partial?

Similar to a partial class, a partial method can be used as a definition in one part while another part can be the implementation. If there is no implementation of the partial method then the method and its calls are removed at compile time. Compiler compiles all parts of a partial method to a single method.

Can partial classes be in different assemblies?

No, you cannot have two partial classes referring to the same class in two different assemblies (projects). Once the assembly is compiled, the meta-data is baked in, and your classes are no longer partial. Partial classes allows you to split the definition of the same class into two files.

What are all the rules to follow when working with partial class definitions?

The partial keyword indicates that other parts of the class, struct, or interface can be defined in the namespace. All the parts must use the partial keyword. All the parts must be available at compile time to form the final type. All the parts must have the same accessibility, such as public , private , and so on.

Do partial classes have to be in same namespace?

You need to use partial keyword in each part of partial class. The name of each part of partial class should be the same but source file name for each part of partial class can be different. All parts of a partial class should be in the same namespace.


2 Answers

Partial methods have to be completely resolvable at compile time. If they are not there at compile time, they are completely missing from the output. The entire reason partial methods work is that removing them has no impact on the API or program flow outside of the one line calling site (which, also, is why they have to return void).

When you add a method to your public API - you're defining a contract for other objects. Since the entire point of a partial method is to make it optional, you'd basically be saying: "I have a contract you can rely on. Oh wait, you can't rely on this method, though."

In order for the public API to be reasonable, the partial method has to really either always be there, or always be gone - in which case it shouldn't be partial.

In theory, the language designers could have changed the way partial methods work, in order to allow this. Instead of removing them from everywhere they were called, they could have implemented them using a stub (ie: a method that does nothing). This would not be as efficient, and is unnecessary for the use case envisioned by partial methods, though.

like image 164
Reed Copsey Avatar answered Oct 06 '22 22:10

Reed Copsey


Instead of asking why are they private, let's rephrase the question to this:

  • What would happen if partial methods weren't private?

Consider this simple example:

public partial class Calculator
{
    public int Divide(int dividend, int divisor)
    {
        try
        {
            return dividend / divisor;
        }
        catch (DivideByZeroException ex)
        {
            HandleException(ex);
            return 0;
        }
    }

    partial void HandleException(ArithmeticException ex);
}

Let's ignore for the moment the question of why we would make this a partial method as opposed to an abstract one (I'll come back to that). What's important is that this compiles - and works correctly - whether the HandleException method is implemented or not. If nobody implements it, this just eats the exception and returns 0.

Now let's change the rules, say that the partial method could be protected:

public partial class Calculator
{
    // Snip other methods

    // Invalid code
    partial protected virtual void HandleException(ArithmeticException ex);
}

public class LoggingCalculator : Calculator
{
    protected override virtual void HandleException(ArithmeticException ex)
    {
        LogException(ex);
        base.HandleException(ex);
    }

    private void LogException(ArithmeticException ex) { ... }
}

We have a bit of a problem here. We've "overridden" the HandleException method, except that there's no method to override yet. And I mean the method literally does not exist, it's not getting compiled at all.

What does it mean what our base Calculator invokes HandleException? Should it invoke the derived (overridden) method? If so, what code does the compiler emit for the base HandleException method? Should it be turned into an abstract method? An empty method? And what happens when the derived method calls base.HandleException? Is this supposed to just do nothing? Raise a MethodNotFoundException? It's really hard to follow the principle of least surprise here; almost anything you do is going to be surprising.

Or maybe nothing should happen when HandleException is invoked, because the base method wasn't implemented. This doesn't seem very intuitive, though. Our derived class has gone and implemented this method and the base class has gone and pulled the rug out from under it without us knowing. I can easily imagine some poor developer pulling his hair out, unable to figure out why his overridden method is never getting executed.

Or maybe this code shouldn't compile at all or should produce a warning. But this has a number of problems of its own. Most importantly, it breaks the contract provided by partial methods, which says that neglecting to implement one should never result in a compiler error. You have a base class which is humming along just fine, and then, by virtue of the fact that someone implemented a totally valid derived class in some completely different part of the application, suddenly your app is broken.

And I haven't even started talking about the possibility of the base and derived classes being in different assemblies. What happens if you reference an assembly with a base class that contains a "public" partial method, and you try to override it in a derived class in another assembly? Is the base method there, or not there? What if, originally, the method was implemented, and we wrote a bunch of code against it, but somebody decided to remove the implementation? The compiler has no way to stub out the partial method calls from referencing classes because as far as the compiler is concerned, that method never existed in the first place. It's not there, it's not in the compiled assembly's IL anymore. So now, simply by removing the implementation of a partial method, which is supposed to have no ill effects, we've gone and broken a whole bunch of dependent code.

Now some people might be saying, "so what, I know that I'm not going to try to do this illegal stuff with partial methods." The thing you have to understand is that partial methods - much like partial classes - are primarily intended to help simplify the task of code generation. It's very unlikely that you would ever want to write a partial method yourself period. With machine-generated code, on the other hand, it's actually fairly likely that consumers of the code will want to "inject" code at various locations, and partial methods provide a clean way of doing this.

And therein lies the problem. If you introduce the possibility of compile-time errors due to partial methods, you've created a situation in which the code generator generates code that doesn't compile. This is a very, very bad situation to be in. Think about what you'd do if your favourite designer tool - say Linq to SQL, or the Winforms or ASP.NET designer, suddenly started producing code that sometimes fails to compile, all because some other programmer created some other class that you've never even seen before that happens to have become a little too intimate with the partial method?

In the end it really boils down to a much simpler question, though: What would public/protected partial methods add that you can't already accomplish with abstract methods? The idea behind partials is that you can put them on concrete classes and they'll still compile. Or rather, they won't compile, but they won't produce an error either, they will just be completely ignored. But if you expect them to be called publicly, then they aren't really "optional" anymore, and if you expect them to be overridden in a derived class, then you might as well just make it abstract or virtual and empty. There isn't really any use for a public or protected partial method, other than to confuse the compiler and the poor bastard trying to make sense of it all.

So instead of opening up that Pandora's box, the team said forget it - public/protected partial methods aren't much use anyway, so just make them private. That way we can keep everything safe and sane. And it is. As long as partial methods stay private, they are easy to understand and worry-free. Let's keep it that way!

like image 25
Aaronaught Avatar answered Oct 06 '22 23:10

Aaronaught