CLR UDT Example: ComplexNumber.cs
System;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using System.Globalization;
/*=====================================================================
File: ComplexNumber.cs
Summary: A Format.Native UDT that represents a complex number
Date: Sep 23, 2003
---------------------------------------------------------------------
This file is part of the Microsoft SQL Server Code Samples.
Copyright (C) Microsoft Corporation. All rights reserved.
This source code is intended only as a supplement to Microsoft
Development Tools and/or on-line documentation. See these other
materials for detailed information regarding Microsoft code samples.
THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
======================================================= */
namespace Microsoft.Samples.SqlServer
{
[Serializable]
[SqlUserDefinedType(Format.Native, IsByteOrdered = true)]
[System.Xml.Serialization.XmlSerializerAssemblyAttribute("ComplexNumber.XmlSerializers, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
public struct ComplexNumber : INullable, IComparable
{
//Regular expression used to parse values that are of the form (1,2i)
private static readonly Regex _parser = new Regex(@"\(\s*(?<real>\-?\d+(\.\d+)?)\s*,\s*(?<img>\-?\d+(\.\d+)?)\s*i\s*\)", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
double _r;
double _i;
bool _isnull;
const string NULL = "<<null complex>>";
static readonly ComplexNumber NULL_INSTANCE = new ComplexNumber(true);
public ComplexNumber(double r, double i)
{
_r = r;
_i = i;
_isnull = false;
}
private ComplexNumber(bool isnull)
{
_isnull = isnull;
_r = _i = 0;
}
public double Real
{
get
{
if (_isnull)
throw new InvalidOperationException();
return _r;
}
set { _r = value; }
}
public double Imaginary
{
get
{
if (_isnull)
throw new InvalidOperationException();
return _i;
}
set { _i = value; }
}
public double Modulus
{
get
{
if (_isnull)
throw new InvalidOperationException();
return Math.Sqrt(_r * _r + _i * _i);
}
}
#region value-based equality
public int CompareTo(object o)
{
if (!(o is ComplexNumber))
return -1;
ComplexNumber c = (ComplexNumber)o;
if (_isnull && c._isnull)
return 0;
if (_isnull || c._isnull)
return -1;
if (_r == c._r && _i == c._i)
return 0;
if (Modulus == c.Modulus) // same modulus but different r/i, force diff
return -1;
// arbitrary comparison...semantics for complex numbers not necessarily correct
return Modulus.CompareTo(c.Modulus);
}
public override bool Equals(object o)
{
return this.CompareTo(o) == 0;
}
public override int GetHashCode()
{
return Modulus.GetHashCode();
}
public static SqlBoolean operator ==(ComplexNumber c1, ComplexNumber c2)
{
return c1.Equals(c2);
}
public static SqlBoolean operator !=(ComplexNumber c1, ComplexNumber c2)
{
return !c1.Equals(c2);
}
public static SqlBoolean operator <(ComplexNumber c1, ComplexNumber c2)
{
return c1.CompareTo(c2) < 0;
}
public static SqlBoolean operator >(ComplexNumber c1, ComplexNumber c2)
{
return c1.CompareTo(c2) > 0;
}
#endregion
public override string ToString()
{
return _isnull ? NULL : ("(" + _r + "," + _i + "i)");
}
public bool IsNull
{
get { return _isnull; }
}
public static ComplexNumber Parse(SqlString s)
{
string value = s.ToString();
if (NULL == value)
return new ComplexNumber(true);
Match m = _parser.Match(value);
if (!m.Success)
throw new ArgumentException("Invalid format for complex number. Format is ( n, mi ) where n and m are floating point numbers");
return new ComplexNumber(double.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture), double.Parse(m.Groups[2].Value, CultureInfo.InvariantCulture));
}
public static ComplexNumber Null
{
get { return NULL_INSTANCE; }
}
}
}