简体   繁体   中英

How to return value from C# partial method?

有没有办法这样做,因为似乎部分方法必须返回 void (我真的不明白这个限制,但就这样吧)?

Well, technically you can "return" a value from a partial method, but it has to be through a ref argument, so it's quite awkward:

partial void Foo(ref int result);

partial void Foo(ref int result)
{
    result = 42;
}

public void Test()
{
    int i = 0;
    Foo(ref i);
    // 'i' is 42.
}

In that example, the value of i won't change if Foo() is not implemented.

From MSDN :

  • Partial method declarations must begin with the contextual keyword partial and the method must return void.

  • Partial methods can have ref but not out parameters.

So the answer is no, you can't.

Perhaps if you explain a bit more about your situation (why you need to return a value, why the class is partial), we can provide a workaround.

You cannot return a value from a partial method.

Partial methods may or may not be implemented. If it were permitted to return a value from such a method, then what would the caller receive?

The reason for the restriction is this line from MSDN :

A partial class or struct may contain a partial method. One part of the class contains the signature of the method. An optional implementation may be defined in the same part or another part. If the implementation is not supplied, then the method and all calls to the method are removed at compile time. -- Emphasis Mine

If the method may not be implemented and can be removed. What would happen to its return value if the call is removed?

As to your question of a work around, that depends on what you are trying to do, but obviously you can't use a partial method.

Oh. Once I had to do this in a project of mine. You can throw an exception in your method called ReturnValueException which you define as an exception that has an object property named ReturnedValue . Now you can call your method Foo() inside a try block and collect the results in the catch block.

No.. just kidding.

Don't do that. Ever.

Here's a technique relying on the fact that an extension method will be shadowed by a class method.

It's more involved and less clear than the ref parameter technique, so I'll use that instead.

Several shadowing mechanisms in C# could be used instead: using static vs. method, a parent class containing just the default behaviour vs. a new method, a method accepting a dummy object vs. a method with a more specific argument type etc.

The choice between the extension method or the class method when it is present is made at compile-time (that is, it doesn't use late binding). This can lead to some problems if your partial class is not sealed: if you override the customizable method with an implementation which is also customizable, you need to use a fresh interface and extension method

https://repl.it/@suzannesoy/WorthwhileSplendidBotany#main.cs

// On the auto-generated side:

interface IDefaultFoo { int DefaultFoo(); }

static class DefaultFoo {
  public static int CustomFoo(this IDefaultFoo o) => o.DefaultFoo();
}

partial class PartialClass : IDefaultFoo {
  int IDefaultFoo.DefaultFoo() => 42;
  // mark as virtual if you want to override in subclasses too.
  public virtual int Foo() => this.CustomFoo();
}

// On the user side:

partial class PartialClass {
  // Define this method only if you want to change
  // the default implementation of Foo.
  public int CustomFoo() => 123;
}

// In subclasses use override on the Foo method as usual
class SubClass1 : PartialClass {
  public new int CustomFoo() => 666; // This is not used
  public override int Foo() => 999;  // Use this instead
}

// If you also want to override in the subclass with a method which
// is also customizable, i.e. to provide a new default behaviour in
// the partial subclass that could also be customized, you'll need
// to add a new interface etc. otherwise the CustomFoo from the
// parent class would be called because it still shadows the
// extension method.
interface IDefaultFooSub2 { int DefaultFoo(); }
static class DefaultFooSub2 {
  public static int CustomFooSub2(this IDefaultFooSub2 o) => o.DefaultFoo();
}
partial class SubClass2 : PartialClass, IDefaultFooSub2 {
  int IDefaultFooSub2.DefaultFoo() => 1000000;
  public override int Foo() => this.CustomFooSub2();
}

class MainClass {
  public static void Main (string[] args) {
    System.Console.WriteLine(new PartialClass().Foo()); // 123
    System.Console.WriteLine(new SubClass1().Foo()); // 999
    System.Console.WriteLine(new SubClass2().Foo()); // 1000000
    System.Console.WriteLine(((PartialClass)new SubClass2()).Foo()); // 1000000
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM