Passing null as an "out" parameter

J

John Layton

Hi there,

Is it possible to pass null to a function taking an "out" (or "ref")
parameter in C#. I'd like to do something like the following (which doesn't
compile of course). Thanks in advance.

int SomeValue;
Func(null, SomeValue); // Any way to pass null for either arg?

void Func(out int Param1, out int Param2)
{
if (Param1 != null)
{
Param1 = Whatever1();
}

if (Param2 != null)
{
Param2 = Whatever2();
}
}
 
P

Paul E Collins

I don't think this is an out vs. ref issue...

Your code won't compile in C# 1.x because null is only an acceptable
value for reference types (ones based on a class, rather than anything
like int, float, or a struct). I'm not overly familiar with the C# 2.0
compiler, but I believe it'll let you have nullable value types if you
append ? to the type name. Does your code work if you use "int?"
rather than "int" ?

Eq.
 
M

Marc Gravell

Well, since you look at the values inside the method, you probably mean
"ref", in which case something like:
int? binMe = null, someValue = 0;
Func(ref binMe, ref someValue); // Any way to pass null for either arg?
Console.WriteLine(binMe);
Console.WriteLine(someValue);
static void Func(ref int? Param1, ref int? Param2) {
if (Param1 != null) Param1 = 7; // random
if (Param2 != null) Param2 = 5; // random
}

It *looks* like you are trying to decide which values to lookup (perhaps
from a DB); in which case, another option is some kind of bitmask, perhaps
in a [Flags] enum.
 
J

John Layton

I don't think this is an out vs. ref issue...
Your code won't compile in C# 1.x because null is only an acceptable value
for reference types (ones based on a class, rather than anything like int,
float, or a struct). I'm not overly familiar with the C# 2.0 compiler, but
I believe it'll let you have nullable value types if you append ? to the
type name. Does your code work if you use "int?" rather than "int" ?

Thanks for the response. Perhaps it was a bad example then since the args
will be reference types in practice (I'm coming from the C++ world where no
such issues exist). If they are reference types then is this doable? Thanks
again.
 
J

John Layton

Marc Gravell said:
Well, since you look at the values inside the method, you probably mean
"ref", in which case something like:
int? binMe = null, someValue = 0;
Func(ref binMe, ref someValue); // Any way to pass null for either arg?
Console.WriteLine(binMe);
Console.WriteLine(someValue);
static void Func(ref int? Param1, ref int? Param2) {
if (Param1 != null) Param1 = 7; // random
if (Param2 != null) Param2 = 5; // random
}

It *looks* like you are trying to decide which values to lookup (perhaps
from a DB); in which case, another option is some kind of bitmask, perhaps
in a [Flags] enum.

Thanks for the response. I'm not sure what the "?" in "int?" does however
(haven't seen this before but will look it up). In any event, passing bit
flags is inconvenient :) In the general case, when one has a function that
returns multiple out arguments and a client is only interested in a subset
of them, the ability to simply pass "null" for the others is very convenient
(and saves you from having to declare variables unnecessarily).
 
B

Bruce Wood

John said:
Marc Gravell said:
Well, since you look at the values inside the method, you probably mean
"ref", in which case something like:
int? binMe = null, someValue = 0;
Func(ref binMe, ref someValue); // Any way to pass null for either arg?
Console.WriteLine(binMe);
Console.WriteLine(someValue);
static void Func(ref int? Param1, ref int? Param2) {
if (Param1 != null) Param1 = 7; // random
if (Param2 != null) Param2 = 5; // random
}

It *looks* like you are trying to decide which values to lookup (perhaps
from a DB); in which case, another option is some kind of bitmask, perhaps
in a [Flags] enum.

Thanks for the response. I'm not sure what the "?" in "int?" does however
(haven't seen this before but will look it up). In any event, passing bit
flags is inconvenient :) In the general case, when one has a function that
returns multiple out arguments and a client is only interested in a subset
of them, the ability to simply pass "null" for the others is very convenient
(and saves you from having to declare variables unnecessarily).

The short answer: no.

However, there is a way to use Marc's bit masks but not pollute your
client code. It involves writing a lot of overloads, and won't work if
several (or all) of your arguments are the same type, but what about
this:

[Flags]
private enum ReturnType = {
ReturnCustomer = 0x01,
ReturnSupplier = 0x02,
...
};

private void Fetch(ReturnType whatToReturn, out Customer cust, out
Supplier supp)
{
if ((whatToReturn & ReturnType.ReturnCustomer) != 0)
{
cust = ... ;
}
if ((whatToReturn & ReturnType.ReturnSupplier) != 0)
{
supp = ... ;
}
}

public void Fetch(out Customer cust, out Supplier supp)
{
Fetch(ReturnType.Customer | ReturnType.Supplier, out cust, out
supp);
}

public void Fetch(out Customer cust)
{
Supplier dummySupplier;
Fetch(ReturnType.Customer, out cust, out dummySupplier);
}

public void Fetch(out Supplier supp)
{
Customer dummyCustomer;
Fetch(ReturnType.Supplier, out dummyCustomer, out supp);
}

As I said, it doesn't work for all scenarios, but it does hide the
declaration of unnecessary variables inside overloaded methods.
 
J

John Layton

Thanks for the suggestion. It looks like I have little choice but it's a
pain IMO :) Anyway, thanks again.
 
M

Marc Gravell

"int?" is a C# shortcut for the 2.0 generic (immutable) struct
Nullable<int>; Nullable<T> (in general) sports a struct T and a bool
(.HasValue) to indicate if it has a value or should be considered null. Note
that since it is a struct it never really *is* null (in the object sense),
but that the compiler infers null equality via the .HasValue property.

Note, however, that you could achieve a similar effect in 1.1 using "magic
numbers", such as int.MinValue to mean "ignore this".

To be honest, however, I'm not really loving this whole approach anyway - it
seems (more than) a bit unsightly; perhaps I'd go for something a whole lot
simpler (ignore names):

public class SomethingResult { // or struct, depending
public int SomeValue;
public float SomeOtherValue;
public bool SomethingElse;
}

[Flags]
pulic enum QueryOptions {
None = 0, SomeValue = 1, SomeOtherValue = 2, SomethingElse = 4, All = 7
}

public SomethingResult DoSomething(QueryOptions options) {
SomethingResult result = new SomethingResult();
if((options & QueryOptions.SomeValue) == QueryOptions.SomeValue)
result.SomeValue = // do something
if((options & QueryOptions.SomeOtherValue) == QueryOptions.SomeOtherValue)
result.SomeOtherValue= // do something
if((options & QueryOptions.SomethingElse ) == QueryOptions.SomethingElse)
result.SomethingElse = // do something
}

You can now just call DoSomething() specifying what you want, and then
inspect the returned object to get the values (only looking at the ones you
asked for; the rest will default to null/0/false). No hastle with ref / out;
no setting up 20 dummy parameters just because you want to read one value;
very friendly, and compatible with both 1.1 and 2.0 runtimes.

Marc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top