tags:

views:

1086

answers:

7

I have a class that contains two methods like these:

public String getFoo(Int32 a)
{
  return getBar(a, "b", null);
}

public String getBar(Int32 a, String b, Int32 c)
{
  //do something
  return "";
}

However when I compile my class I get two errors:

  1. The best overloaded method match for getBar(int,string,int) has some invalid arguments
  2. Argument '3': cannot convert from '<null>' to 'int'

I think I understand why I'm getting this error: the compiler doesn't know at the time of compilation what the real type of the object is. Can someone confirm if I'm correct about the cause of the error or point out the real reason?

More importantly, can I design my code this way? If so, what do I need to do to fix the errors? My reason for designing my class this way is because I don't want to duplicate the code in getBar, in getFoo. The two methods do essentially the same thing except one takes a third parameter.

Thanks.

+1  A: 

Int32 is a value type, which means null is not a valid argument for parameters of type Int32.

If you really need nullable ints, use the int? type.

The two errors you are seeing are actually the same error.

Jacob
+2  A: 

Try making the third argument to the getBar a nullable int.

So, the signature would look like this:

public String getBar(Int32 a, String b, Int32? c)

You can find out more about nullable types in .NET here and here.

jerhinesmith
+7  A: 

In .NET, there is a distinct concept between reference types and value types.

A reference type is an object that is allocated on the heap (It will be a subclass of System.Object). All that is on the stack is a pointer to this object. Because of that, it is perfectly valid to store a null pointer.

A value type is an object that is allocated on the stack, it will be a subclass of System.ValueType. Because a value type lives on the stack, when you pass its value to a function, you pass the entire contents of the object.

Value types cannot be null.

Most C# primitive types are value types. String is a special type of primitive that is actually a reference type.

In .NET 2.0, MS added the ability to enclose a generic type inside of a struct so that it could simulate a nullable type. What really happens is that the logic inside of the Nullable<T> struct is emulating a null for you.

They expressed it using a syntax shortcut by adding a question mark to the type, for example:

int? nullableInt = null;
float? nullableFloat = null;

etc...

If you don't like the int? syntax, you can always use Nullable<SomeType>

public String getBar(Int32 a, String b, Nullable<Int32> c)

As a side note, I prefer to add an overload when doing what you are doing, just to make the syntax nicer.

public String getBar(Int32 a, String b)
{
     this.getBar(a,b,null);
}

public String getBar(Int32 a, String b, Nullable<Int32> c)
{
}
FlySwat
This is a great answer. I come back to it every now and then.
Notorious2tall
+1  A: 

Int32 is an alias for int which is a value/non-nullable type. For a nullable version of it use System.Nullable or simply 'int?'.

Also don't forget to convert back to a non-nullable int:

i

nt? nullable = ...;
int non_nullable = nullable??0;

where the number indicates what value it should assume if it is indeed null.

George Mauer
+1  A: 

Sunny is correct.
Int32 is a value type and can not hold the value 'null'. If you need to pass 'null' as a parameter value, use Nullable instead of Int32 as your argument type.

You can find more information at Nullable Types (C# Programming Guide) on MSDN.

svlists
Specifically, Int32 is a value type and null is never a valid value for a value type. Null is only valid for reference types, which is anything that inherits from System.Object.
cfeduke
A: 

Int32 cannot be null. Make it a nullable type instead:

public String getBar(Int32 a, String b, Int32? c)
{
    if (c.HasValue)
    {
        ...do something with c.Value...
    }
    return "";
}
Tim Scott
A: 

OK, so fiveseven people proposed int? as the solution. I propose two other solutions that might be more appropriate, depending on the situation;

  • Create an overload of the method that only has two arguments, and omit the null when calling:

    public String getFoo(Int32 a)
    {
      return getBar(a, "b", null);
    }
    
    
    public String getBar(Int32 a, String b)
    {
      //do something else, without the int
    }
    

    Although you probably don't want to do this since you stated that you wanted to avoid code duplication.

  • Use default instead of null:

    return getBar(a, "b", default(int));
    

    Incidentally, this is the same as passing the value 0.

Konrad Rudolph
His overload would still need a nullable type, or a lot of code duplication.
FlySwat