Previous Thread:   IsNull property on UDTs

1/22/2006 1:04:58 PM    Re: DECLARE @Var1 NEW Point!
"Leila" <Leilas@hotpop.com> wrote in  
  
news:O20JPN5HGHA.2064@TK2MSFTNGP09.phx.gbl:  
  
Well, if you use the Null property you are getting back a null instance  
  
(i.e not instantiated), so when you try to use it, you'll get an error  
  
that whatever you try to do can not be called on a null value. Think  
  
about a "normal" CLR type, you have to properly instantiate it before  
  
you use it.  
  
Niels  
  
--  
  
**************************************************  
  
* Niels Berglund  
  
* http://staff.develop.com/nielsb  
  
* nielsb@no-spam.develop.com  
  
* "A First Look at SQL Server 2005 for Developers"  
  
* http://www.awprofessional.com/title/0321180593  
  
**************************************************



1/22/2006 6:32:18 PM    Re: DECLARE @Var1 NEW Point!
Did not see your whole point type, but does not seem like your implementing  
  
it right in terms of isNull bool.  You may also want to concider a  
  
non-mutable Point.  So you can't change x or y after construction.  You just  
  
create new point instances (ala String, SqlDateTime, etc).  
  
--Test  
  
declare @p Point  
  
set @p = Point::GetNewPoint(1,2)  
  
select @p.ToString()  
  
set @p.Y = 3  
  
select @p.ToString()  
  
-- Point UDT  
  
using System;  
  
using System.Data.Sql;  
  
using System.Data.SqlTypes;  
  
using Microsoft.SqlServer.Server;  
  
[Serializable]  
  
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native, IsByteOrdered  
  
= true)]  
  
public struct Point : INullable  
  
{  
  
private int x;  
  
private int y;  
  
private bool isNull;  
  
public Point(int x, int y)  
  
{  
  
this.x = x;  
  
this.y = y;  
  
this.isNull = false;  
  
}  
  
public static Point GetNewPoint(int x, int y)  
  
{  
  
return new Point(x, y);  
  
}  
  
public Int32 X  
  
{  
  
get  
  
{  
  
if (IsNull)  
  
throw new SqlNullValueException();  
  
return this.x;  
  
}  
  
[SqlMethod(IsMutator = true)]  
  
set  
  
{  
  
if ( IsNull )  
  
throw new SqlNullValueException();  
  
this.x = value;  
  
}  
  
}  
  
public Int32 Y  
  
{  
  
get  
  
{  
  
if (IsNull)  
  
throw new SqlNullValueException();  
  
return this.y;  
  
}  
  
[SqlMethod(IsMutator = true)]  
  
set  
  
{  
  
if (IsNull)  
  
throw new SqlNullValueException();  
  
this.y = value;  
  
}  
  
}  
  
public bool IsNull  
  
{  
  
get  
  
{  
  
return (this.isNull);  
  
}  
  
}  
  
public static Point Null  
  
{  
  
get  
  
{  
  
Point pt = new Point();  
  
pt.isNull = true;  
  
return pt;  
  
}  
  
}  
  
public override string ToString()  
  
{  
  
if (this.IsNull)  
  
return "NULL";  
  
return x + "," + y;  
  
}  
  
[SqlMethod(OnNullCall = false)]  
  
public static Point Parse(SqlString s)  
  
{  
  
if (s.IsNull)  
  
return Point.Null;  
  
string[] xy = s.Value.Split(",".ToCharArray());  
  
int x = Int32.Parse(xy[0]);  
  
int y = Int32.Parse(xy[1]);  
  
return new Point(x, y);  
  
}  
  
}  
  
--  
  
William Stacey [MVP]

1/23/2006 12:03:23 AM    DECLARE @Var1 NEW Point!
Hi,  
  
About two month ago, I read a discussion here and one of the gurus had  
  
suggested to write a shared method in UDT that instantiates an empty UDT to  
  
return it for caller:  
  
Public Shared Function GetNewPoint() As Point  
  
Dim tmp As New Point  
  
Return tmp  
  
End Function  
  
and then use it in our script:  
  
DECLARE @a point  
  
SET @a=point::GetNewPoint()  
  
I'm wondered that why not to use Null property of UDT?  
  
DECLARE @a point  
  
SET @a=point::[Null]  
  
Are there any advantage over Null property when we write our own method for  
  
this purpose?  
  
Thanks in advance,  
  
Leila

1/23/2006 1:05:26 AM    Re: DECLARE @Var1 NEW Point!
Thanks Niels,  
  
I have implemented IsNull something like this:  
  
Public ReadOnly Property IsNull() As Boolean Implements INullable.IsNull  
  
Get  
  
If X.IsNull = False And Y.IsNull = False Then  
  
Return False  
  
Else  
  
Return True  
  
End If  
  
End Get  
  
End Property  
  
And my method for getting a new instance of UDT is:  
  
Public Shared Function GetNewPoint() As Point  
  
Dim tmp As New Point  
  
tmp.m_Null = False  
  
Return tmp  
  
End Function  
  
I have problem with the last line of this script:  
  
DECLARE @P1 point  
  
SET @P1=point::GetNewPoint()  
  
SET @P1.X=1  
  
The error I get is:  
  
Mutator 'X' on '@P1' cannot be called on a null value.  
  
If I comment the code in IsNull property, the error does not appear. So  
  
what's the relation between "SET @P1.X=1" and "IsNull" ?  
  
Thanks again,  
  
Leila  
  
"Niels Berglund" <nielsb@develop.com> wrote in message  
  
news:Xns9753D675379C4nielsbdevelopcom@207.46.248.16...

1/23/2006 10:52:14 AM    Re: DECLARE @Var1 NEW Point!
Couple things.  
  
1) I am curious why you testing x and y for null?  The object is either null  
  
or it is not.  Just set and test a isNull bool like I showed.  If your not  
  
allowing null points, then IsNull never really needs to be called.  I might  
  
even throw an error in Null getter if I never wanted a Null point.  
  
2) IMO, GetNewPoint() would be generally more useful if you allowed  
  
arguments like GetNewPoint(x, y).  And faster then wrapping Parse, because  
  
you don't need to parse anything.  Also, it saves code as you don't have to  
  
set X and Y after using GetNewPoint().  
  
--  
  
William Stacey [MVP]  
  
"Leila" <Leilas@hotpop.com> wrote in message  
  
news:ulbPn5AIGHA.1728@TK2MSFTNGP09.phx.gbl...

1/23/2006 2:44:34 PM    Re: DECLARE @Var1 NEW Point!
Thanks William,  
  
I read this blog entry:  
  
http://blogs.msdn.com/sqlclr/archive/2005/06/21/431329.aspx  
  
It seems that I can get my desired behavior from IsNull property only when  
  
the UDT is deserialized.  
  
Therefore I must call Parse within GetNewPoint. I changed this method to:  
  
Public Shared Function GetNewPoint() As Point  
  
Dim tmp As Point = Parse("0:0")  
  
Return tmp  
  
End Function  
  
My IsNull property:  
  
Public ReadOnly Property IsNull() As Boolean Implements INullable.IsNull  
  
Get  
  
If X.IsNull = False And Y.IsNull = False Then  
  
Return False  
  
Else  
  
Return True  
  
End If  
  
End Get  
  
End Property  
  
Is working fine and:  
  
DECLARE @P1 point  
  
SET @P1=point::GetNewPoint()  
  
SET @P1.X=1  
  
Does not raise error. Is my job right or I'm missing something?  
  
Thanks again,  
  
Leila  
  
"William Stacey [MVP]" <william.stacey@gmail.com> wrote in message  
  
news:uE9GZw6HGHA.648@TK2MSFTNGP14.phx.gbl...

1/24/2006 1:11:20 AM    Re: DECLARE @Var1 NEW Point!
"Leila" <Leilas@hotpop.com> wrote in news:ulbPn5AIGHA.1728  
  
@TK2MSFTNGP09.phx.gbl:  
  
As William points out; I don't understand why you are using the x and y for  
  
checking for Null. Use the boolean flag instead. If you did that, you would  
  
not run into the issues you had in the first place.  
  
Niels  
  
--  
  
**************************************************  
  
* Niels Berglund  
  
* http://staff.develop.com/nielsb  
  
* nielsb@no-spam.develop.com  
  
* "A First Look at SQL Server 2005 for Developers"  
  
* http://www.awprofessional.com/title/0321180593  
  
**************************************************