Nullable types in a constructor?

S

Steven Livingstone

Bit of advice here folks.

I am creating a default constructor that just initializes a new instance of
my object and a secon constructor that takes an ID and loads an object with
data from the database for the given ID. I could just leave two separate
constructors, or i could just have the default one call the second with a
"-1" as the ID. This means that the initialization of certain fields can be
based on whether my ID is -1 (for lazy loading and so on).

Here is my question.... i'd like to make use of a nullable int in this case,
so rather than passing -1 as my default value when calling the second
constructor from the first, i can pass null.

Is this good practice, especially in public constructors/interfaces to use
int? (realize how hard it is to end this sentence with a question mark now -
but it IS a question!! :)

Here is a rough example of what i'm harping on about (for a class "Element")
........

public Element() : this(null) { }

public Element(int? elementid)
{
InitializeObject();

if (elementid != null)
SetUpObject(elementid);
}

The alternative is to use -1 in public interfaces and use null internally,
but that's kinda daft. I'd rather be consistent with one or the other. In
other words, for a number of the constructors that i DO have, which all are
public, can i (or is it a good idea to) use int? and so on rather than the
traditional int??

At a more advanced level - is it part of the CLI? Are there limitations i am
going to run into?
What kind of support with web services, wsdl, schema (well xml schema doe
support null's) as generated from .Net is there for int?

thanks,
steven :: http://stevenR2.com
 
J

Jon Skeet [C# MVP]

Steven said:
Bit of advice here folks.

I am creating a default constructor that just initializes a new instance of
my object and a secon constructor that takes an ID and loads an object with
data from the database for the given ID. I could just leave two separate
constructors, or i could just have the default one call the second with a
"-1" as the ID. This means that the initialization of certain fields can be
based on whether my ID is -1 (for lazy loading and so on).

Here is my question.... i'd like to make use of a nullable int in this case,
so rather than passing -1 as my default value when calling the second
constructor from the first, i can pass null.

Is this good practice, especially in public constructors/interfaces to use
int? (realize how hard it is to end this sentence with a question mark now -
but it IS a question!! :)

I think it depends on the context, as you rightly questioned later.

I wouldn't use a generic type (which nullable types are) in any
web-service definitions - that's just asking for trouble. I'm not
saying they won't work, but it sounds like a bad idea to me.

Nullable types appear to be CLS-compliant, in that that compiler
doesn't complain about a type with a constructor taking an int?
parameter, so I would feel comfortable using it for anything which
doesn't need to interoperate with other platforms.

Jon
 
S

Steven Livingstone

Thanks Jon -

that's not too bad - it is typical that my web service interfaces sit as a
layer on top of my business services layer anyway.
I can make -1 a null at that point i guess.

Hmmmm - whilst writing read a little and ran a test. .Net uses xsi:nil for
nullable value types in serialization.

The WSDL interface that is generated can use xsi:nil for elements i defined
to be nullable value types
in my interface!? That would make it pretty cross platform i would hope.

That makes things a little easier i guess and definitely encourages me to
use them!

steven :: http://stevenR2.com
 
J

Jon Skeet [C# MVP]

Steven said:
that's not too bad - it is typical that my web service interfaces sit as a
layer on top of my business services layer anyway.
I can make -1 a null at that point i guess.

Hmmmm - whilst writing read a little and ran a test. .Net uses xsi:nil for
nullable value types in serialization.

The WSDL interface that is generated can use xsi:nil for elements i defined
to be nullable value types
in my interface!? That would make it pretty cross platform i would hope.

That makes things a little easier i guess and definitely encourages me to
use them!

Well, I wouldn't assume it'll work cross-platform without trying it. At
the very least, try consuming the web service from Java - see what
comes out. In fact, Java may well cope by using java.lang.Integer
(which is a reference type) rather than "int". Just don't forget that
it's not a case of what can go across SOAP/whatever, but also what
languages can consume that WSDL to generate the right requests.

Jon
 
S

Steven Livingstone

This post started as a few lines and expanded to some off topic thoughts on
my frustrations with nullable value types - please comment if you wish and
i blogged it here :
http://stevenr2.blogspot.com/2006/01/nullable-value-types-irritation.html

I have to say working with these things is a little irritating. Mainly
because you can't go implcitly from int? to int and so although in the
context of your Entity you may allow a null ID, the concept of a null ID may
NOT be something you wish to expose to method calls using the object or at
least avoid you having to type everything int? and then check hasValue.

Here's is what I am talking about.

You define a simple element entity as follows:

public class Element
{
int? _id = null;

public int? ID
{
get { return _id;}
set {_id=value;}
}
}


You then may have a data object as follows:

public class MyData
{
public void Save(Element element)
{
if (element.ID == null)
SaveNew(...);
else
Update(...);
}
}

The issue you now have is that any business methods, helper methods and so
on that use this ID can then expect two types of query. The first is where
you have a valid ID (number > 0) and the second is where you have a null
value. Therefore, everytime you want to call a method such as the following,
which will pass the ID of the element to the method you ALWAYS have to do
hasValue.

public class MyBusiness
{
public void AttachToItem(int? id)
{
if (!id.hasValue)
throw new Exception("...");

//Do Something ....
}
}

Yes, before we had to do a check for -1 or some other magic number, but i'd
rather there was an up front way of saying - in this certain scope it may be
nullable, but outside it must have a value before it can be used as a
parameter and the above method defined as follows:

public class MyBusiness
{
public void AttachToItem(int id) //i now have a valid int !
{
if (!id.hasValue)
throw new Exception("...");

//Do Something ....
}
}

The only way i can think of solving this without writing loads of code,
would be to have some kind of c#meta which allows you to put constraints on
the variables in terms of scope, value, casting and exception.

So I may define my nullable int? as follows (making all this up now):

int? _id = null : valuecast(condition[value>0], IDException);


This basically says, define my _id variable as a nullable int? and when it
is cast to an int value - [ in order to solving having to check for nulls in
all my methods and so allow then to be defined as proper int value types ] -
if the current value of _id is not greater than 0 then throw the user
defined IDException.

Something like this would then provide me with a way of casting all of my
fields for my entity throughout my entire application, which allows me to
ensure that i do have a valid int (and it is NOT null) which is needed is
almost all of my cases and my interfaces outside my entity can just use
int's to define their interfaces.

steven :: http://stevenR2.com
 
J

Jay B. Harlow [MVP - Outlook]

Steven,
| public class MyBusiness
| {
| public void AttachToItem(int? id)
| {
| if (!id.hasValue)
| throw new Exception("...");
|
| //Do Something ....
| }
| }
You can simply use id.Value in "//Do Something ....", it will throw an
exception for you if id.HasValue is false.

For example:

int? id = null;
int value = id.Value;

Will throw InvalidOperationException("Nullable object must have a value")
for you on the second line!

Unfortunately it won't handle the id.Value > 0 trick.

--
Hope this helps
Jay [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


| This post started as a few lines and expanded to some off topic thoughts
on
| my frustrations with nullable value types - please comment if you wish
and
| i blogged it here :
| http://stevenr2.blogspot.com/2006/01/nullable-value-types-irritation.html
|
| I have to say working with these things is a little irritating. Mainly
| because you can't go implcitly from int? to int and so although in the
| context of your Entity you may allow a null ID, the concept of a null ID
may
| NOT be something you wish to expose to method calls using the object or at
| least avoid you having to type everything int? and then check hasValue.
|
| Here's is what I am talking about.
|
| You define a simple element entity as follows:
|
| public class Element
| {
| int? _id = null;
|
| public int? ID
| {
| get { return _id;}
| set {_id=value;}
| }
| }
|
|
| You then may have a data object as follows:
|
| public class MyData
| {
| public void Save(Element element)
| {
| if (element.ID == null)
| SaveNew(...);
| else
| Update(...);
| }
| }
|
| The issue you now have is that any business methods, helper methods and so
| on that use this ID can then expect two types of query. The first is where
| you have a valid ID (number > 0) and the second is where you have a null
| value. Therefore, everytime you want to call a method such as the
following,
| which will pass the ID of the element to the method you ALWAYS have to do
| hasValue.
|
| public class MyBusiness
| {
| public void AttachToItem(int? id)
| {
| if (!id.hasValue)
| throw new Exception("...");
|
| //Do Something ....
| }
| }
|
| Yes, before we had to do a check for -1 or some other magic number, but
i'd
| rather there was an up front way of saying - in this certain scope it may
be
| nullable, but outside it must have a value before it can be used as a
| parameter and the above method defined as follows:
|
| public class MyBusiness
| {
| public void AttachToItem(int id) //i now have a valid int !
| {
| if (!id.hasValue)
| throw new Exception("...");
|
| //Do Something ....
| }
| }
|
| The only way i can think of solving this without writing loads of code,
| would be to have some kind of c#meta which allows you to put constraints
on
| the variables in terms of scope, value, casting and exception.
|
| So I may define my nullable int? as follows (making all this up now):
|
| int? _id = null : valuecast(condition[value>0], IDException);
|
|
| This basically says, define my _id variable as a nullable int? and when it
| is cast to an int value - [ in order to solving having to check for nulls
in
| all my methods and so allow then to be defined as proper int value
types ] -
| if the current value of _id is not greater than 0 then throw the user
| defined IDException.
|
| Something like this would then provide me with a way of casting all of my
| fields for my entity throughout my entire application, which allows me to
| ensure that i do have a valid int (and it is NOT null) which is needed is
| almost all of my cases and my interfaces outside my entity can just use
| int's to define their interfaces.
|
| steven :: http://stevenR2.com
|
|
 
S

Steven Livingstone

Thanks Jay.

I realized that, but it would be nice to tie some custom business logic to
this exception as the casting isn't really an error in my case - rather an
exception case when you have just initialized your entity.

I guess it's just hard to support nulables and have valid values on the
public interfaces to the object.

steven :: http://stevenR2.com

Jay B. Harlow said:
Steven,
| public class MyBusiness
| {
| public void AttachToItem(int? id)
| {
| if (!id.hasValue)
| throw new Exception("...");
|
| //Do Something ....
| }
| }
You can simply use id.Value in "//Do Something ....", it will throw an
exception for you if id.HasValue is false.

For example:

int? id = null;
int value = id.Value;

Will throw InvalidOperationException("Nullable object must have a value")
for you on the second line!

Unfortunately it won't handle the id.Value > 0 trick.

--
Hope this helps
Jay [MVP - Outlook]
.NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


| This post started as a few lines and expanded to some off topic thoughts
on
| my frustrations with nullable value types - please comment if you wish
and
| i blogged it here :
|
http://stevenr2.blogspot.com/2006/01/nullable-value-types-irritation.html
|
| I have to say working with these things is a little irritating. Mainly
| because you can't go implcitly from int? to int and so although in the
| context of your Entity you may allow a null ID, the concept of a null ID
may
| NOT be something you wish to expose to method calls using the object or
at
| least avoid you having to type everything int? and then check hasValue.
|
| Here's is what I am talking about.
|
| You define a simple element entity as follows:
|
| public class Element
| {
| int? _id = null;
|
| public int? ID
| {
| get { return _id;}
| set {_id=value;}
| }
| }
|
|
| You then may have a data object as follows:
|
| public class MyData
| {
| public void Save(Element element)
| {
| if (element.ID == null)
| SaveNew(...);
| else
| Update(...);
| }
| }
|
| The issue you now have is that any business methods, helper methods and
so
| on that use this ID can then expect two types of query. The first is
where
| you have a valid ID (number > 0) and the second is where you have a null
| value. Therefore, everytime you want to call a method such as the
following,
| which will pass the ID of the element to the method you ALWAYS have to
do
| hasValue.
|
| public class MyBusiness
| {
| public void AttachToItem(int? id)
| {
| if (!id.hasValue)
| throw new Exception("...");
|
| //Do Something ....
| }
| }
|
| Yes, before we had to do a check for -1 or some other magic number, but
i'd
| rather there was an up front way of saying - in this certain scope it
may
be
| nullable, but outside it must have a value before it can be used as a
| parameter and the above method defined as follows:
|
| public class MyBusiness
| {
| public void AttachToItem(int id) //i now have a valid int !
| {
| if (!id.hasValue)
| throw new Exception("...");
|
| //Do Something ....
| }
| }
|
| The only way i can think of solving this without writing loads of code,
| would be to have some kind of c#meta which allows you to put constraints
on
| the variables in terms of scope, value, casting and exception.
|
| So I may define my nullable int? as follows (making all this up now):
|
| int? _id = null : valuecast(condition[value>0], IDException);
|
|
| This basically says, define my _id variable as a nullable int? and when
it
| is cast to an int value - [ in order to solving having to check for
nulls
in
| all my methods and so allow then to be defined as proper int value
types ] -
| if the current value of _id is not greater than 0 then throw the user
| defined IDException.
|
| Something like this would then provide me with a way of casting all of
my
| fields for my entity throughout my entire application, which allows me
to
| ensure that i do have a valid int (and it is NOT null) which is needed
is
| almost all of my cases and my interfaces outside my entity can just use
| int's to define their interfaces.
|
| steven :: http://stevenR2.com
|
|
 

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