Pages

2012-03-23

DOTNET: Implementing implicit and explicit conversion operator methods


You can specify how your type is converted to other types and, equally, how other types are converted to
your type, by declaring conversion operators in your class. A conversion operator is a static method that
is named for the type that you wish to convert to and that has the type you wish to convert from. For
example, the following method fragment is a conversion operator from the myClass type that converts
an instance of string to an instance of myClass (String TO myClass):

public static explicit operator myClass(string str)
{
return new myClass() 
this.Text = str 
};
}

Defining this member in the myClass class allows us to perform conversions such as the following:

myClass C1 = (myClass)"Hello";

Note that we have had to explicitly cast the string to myClass—this is because our conversion operator
included the explicit keyword. You can enable implicit conversion by using the implicit keyword, such
as this:

public static implicit operator myClass(string str)
{
return new myClass() 
this.Text = str 
};
}

With the implicit keyword, now both of the following statements would compile:
myClass C1 = (myClass)"Hello";
myClass C2 = "Hello";

Conversion operators must always be static, and you must choose between an explicit and an
implicit conversion—you cannot define different conversion operators for the same pair of types but
with different keywords.

DOTNET: Overloading operators


To implement operators in your classes, you simply define static methods to overload the operator you
want to use—for example, the following fragment shows the declaration of a method that implements
the addition operator (+) to be used when adding together two instances of the type myClass:

public static string operator +(myClass C1, myClass w2)

Notice that the result of our addition is a string—you can return any type you choose. You can also
define the behavior for when operators are applied on different types, such as the following, which
declares a method that overrides the operator for when an instance of myClass and an int are added
together:

public static myClass operator +(myClass C1, int i)

The following fragment allows us to use the operator like this:

myClass newMyClass = C1 + 7;

Note that the order of the arguments is important—the previous fragment defines the behavior for a
myClass + int operation, but not int + myClass (i.e., the same types, but with their order reversed). We would need to define another method to support both orderings.

You can override the following operators:
+, -, *, /, %, &, |, ^, <<, >>

DOTNET: Create and Use a Code Module


So you need to do one or more of the following:
  • Improve your application’s performance and memory efficiency by ensuring that  the runtime loads rarely used types only when they are required
  • Compile types written in C# to a form you can build into assemblies being developed in other .NET languages
  • Use types developed in another language and build them into your C# assemblies



OK, build your C# source code into a module by using the command-line compiler and specifying the
/target:module compiler switch. To incorporate an existing module into your assembly, use the
/addmodule compiler switch.



Modules are the building blocks of .NET assemblies. Modules consist of a single file that contains the
following:
  • Microsoft Intermediate Language (MSIL) code created from your source code during compilation

  • Metadata describing the types contained in the module
  • Resources, such as icons and string tables, used by the types in the module



However, the C# compiler can’t compile your Microsoft Visual Basic .NET or
COBOL .NET code for inclusion in your assembly. To use code written in another
language, you can compile it into a separate assembly and reference it. But if you
want it to be an integral part of your assembly, then you must build it into a
module. Similarly, if you want to allow others to include your code as an integral
part of their assemblies, you must compile your code as modules. When you use
modules, because the code becomes part of the same assembly, members marked
as internal or protected internal are accessible, whereas they would not be if the
code had been accessed from an external assembly.

2012-03-08

ADO.NET: Building C# User-Defined Functions in SQL Server


A function in SQL Server is just that: a function that can be invoked from within any T-SQL statement that will return a value. SQL Server has many built-in functions for string concatenation, mathematics, data type conversion, and much more. With the integration of the CLR into SQL Server 2005, you can now write your own user-defined functions in C#.

To illustrate this, without getting bogged down in a complex calculation, the next example will create a C# user-defined function that takes a customer's first name, last name, and middle initial as parameters, and returns a string containing the appropriate full-name display.

using System;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString NameDisplay(
    SqlString firstName,
    SqlString lastName,
    SqlString middleInitial)
{
    // we have access to the StringBuilder, a much better
    // concatenator than string addition
    StringBuilder sb = new StringBuilder();
    sb.AppendFormat("{0}, {1} {2}",
        lastName, firstName, middleInitial);
    return new SqlString(sb.ToString());
}
};


ADO.NET: Building C# Stored Procedures in SQL Server

When creating managed code that will reside within SQL Server as a stored procedure, you are basically creating a static method on a class. That static method is then decorated with the Microsoft.SqlServer.Server.SqlProcedure attribute. 

When your assembly is deployed to SQL Server and stored within the database, this attribute allows SQL to create a CLR routine for the method.

Whenever you add a new stored procedure to your SQL Server project, it will be part of the partial class StoredProcedures and the static method representing the procedure will be in its own file.


By default, SQL Server 2005 doesn't allow you to execute CLR code, so you'll have to enable it by executing the following command inside a SQL query window (make sure you're connected with sufficient privileges to perform this command):
sp_configure 'clr enable', 1
After executing this, SQL Server will inform you that the option has changed, but it will not take effect until you issue the following command:

reconfigure
Now, here is the code of our CLR stored procedure:
using System;using System.Data;using System.Data.SqlClient;using System.Data.SqlTypes;using Microsoft.SqlServer.Server;
public partial class StoredProcedures{
[Microsoft.SqlServer.Server.SqlProcedure]public static void MyCLRStoredProcedure(out SqlString outVal)
{
outVal = "Hello World";
}
};
When building C# static methods that will be used as stored procedures, you need to remember the following rules:
  • The return type of the method is used as the return value of the stored procedure or function.
  • The parameter list of the method is the parameter list of the stored procedure. As such, you should only use data types from the System.Data.SqlTypes namespace.
  • Keep in mind that your method has no user interface, so any debugging or tracing you do can't go to a console window. You can still print debug messages the same way you could with stored procedures, however.


When writing stored procedures, types, functions, and more, you will need access to data and functionality provided by SQL Server. For example, when writing a C# stored procedure you need to be able to send results out on the "pipe." Also, you will want to be able to run your queries using the existing server-side connection and not have to resort to a client-side ADO.NET connection. All of this is available for you in a few classes, such as SqlContext and SqlPipe.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;


public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void RadarScan(int UserID)
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
    conn.Open();
    SqlCommand cmd = conn.CreateCommand();
    cmd.CommandText =
"SELECT FitstName, LastName FROM Contacts WHERE ID = " + UserID.ToString();
    //SqlDataReader rdr = cmd.ExecuteReader();
    //if (rdr.Read())
    //{
        
    //}
    SqlContext.Pipe.ExecuteAndSend(scanCmd);
rdr.Close(); } // no need to explicitly shut down connection because of 'using' statement } };