C# 4.0 optional out/ref arguments

ε祈祈猫儿з 提交于 2019-11-26 19:39:16

As already mentioned, this is simply not allowed and I think it makes a very good sense. However, to add some more details, here is a quote from the C# 4.0 Specification, section 21.1:

Formal parameters of constructors, methods, indexers and delegate types can be declared optional:

fixed-parameter:
    attributesopt parameter-modifieropt type identifier default-argumentopt
default-argument:
    = expression

  • A fixed-parameter with a default-argument is an optional parameter, whereas a fixed-parameter without a default-argument is a required parameter.
  • A required parameter cannot appear after an optional parameter in a formal-parameter-list.
  • A ref or out parameter cannot have a default-argument.

No.

A workaround is to overload with another method that doesn't have out / ref parameters, and which just calls your current method.

public bool SomeMethod(out string input)
{
    ...
}

// new overload
public bool SomeMethod()
{
    string temp;
    return SomeMethod(out temp);
}

Update: If you have C# 7.0, you can simplify:

// new overload
public bool SomeMethod()
{
    return SomeMethod(out _);    // declare out as an inline discard variable
}

(Thanks @Oskar / @Reiner for pointing this out.)

No, but another great alternative is having the method use a generic template class for optional parameters as follows:

public class OptionalOut<Type>
{
    public Type Result { get; set; }
}

Then you can use it as follows:

public string foo(string value, OptionalOut<int> outResult = null)
{
    // .. do something

    if (outResult != null) {
        outResult.Result = 100;
    }

    return value;
}

public void bar ()
{
    string str = "bar";

    string result;
    OptionalOut<int> optional = new OptionalOut<int> ();

    // example: call without the optional out parameter
    result = foo (str);
    Console.WriteLine ("Output was {0} with no optional value used", result);

    // example: call it with optional parameter
    result = foo (str, optional);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional.Result);

    // example: call it with named optional parameter
    foo (str, outResult: optional);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional.Result);
}
wizard07KSU

There actually is a way to do this that is allowed by C#. This gets back to C++, and rather violates the nice Object-Oriented structure of C#.

USE THIS METHOD WITH CAUTION!

Here's the way you declare and write your function with an optional parameter:

unsafe public void OptionalOutParameter(int* pOutParam = null)
{
    int lInteger = 5;
    // If the parameter is NULL, the caller doesn't care about this value.
    if (pOutParam != null) 
    { 
        // If it isn't null, the caller has provided the address of an integer.
        *pOutParam = lInteger; // Dereference the pointer and assign the return value.
    }
}

Then call the function like this:

unsafe { OptionalOutParameter(); } // does nothing
int MyInteger = 0;
unsafe { OptionalOutParameter(&MyInteger); } // pass in the address of MyInteger.

In order to get this to compile, you will need to enable unsafe code in the project options. This is a really hacky solution that usually shouldn't be used, but if you for some strange, arcane, mysterious, management-inspired decision, REALLY need an optional out parameter in C#, then this will allow you to do just that.

ICYMI: Included on the new features for C# 7.0 enumerated here, "discards" is now allowed as out parameters in the form of a _, to let you ignore out parameters you don’t care about:

p.GetCoordinates(out var x, out _); // I only care about x

P.S. if you're also confused with the part "out var x", read the new feature about "Out Variables" on the link as well.

No, but you can use a delegate (e.g. Action) as an alternative.

Inspired in part by Robin R's answer when facing a situation where I thought I wanted an optional out parameter, I instead used an Action delegate. I've borrowed his example code to modify for use of Action<int> in order to show the differences and similarities:

public string foo(string value, Action<int> outResult = null)
{
    // .. do something

    outResult?.Invoke(100);

    return value;
}

public void bar ()
{
    string str = "bar";

    string result;
    int optional = 0;

    // example: call without the optional out parameter
    result = foo (str);
    Console.WriteLine ("Output was {0} with no optional value used", result);

    // example: call it with optional parameter
    result = foo (str, x => optional = x);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional);

    // example: call it with named optional parameter
    foo (str, outResult: x => optional = x);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional);
}

This has the advantage that the optional variable appears in the source as a normal int (the compiler wraps it in a closure class, rather than us wrapping it explicitly in a user-defined class).

The variable needs explicit initialisation because the compiler cannot assume that the Action will be called before the function call exits.

It's not suitable for all use cases, but worked well for my real use case (a function that provides data for a unit test, and where a new unit test needed access to some internal state not present in the return value).

Use an overloaded method without the out parameter to call the one with the out parameter for C# 6.0 and lower. I'm not sure why a C# 7.0 for .NET Core is even the correct answer for this thread when it was specifically asked if C# 4.0 can have an optional out parameter. The answer is NO!

What about like this?

public bool OptionalOutParamMethod([Optional] ref string pOutParam)
{
    return true;
}

You still have to pass a value to the parameter from C# but it is an optional ref param.

void foo(ref int? n)
{
    return null;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!