.NET Generics
Just wanted to share with everyone the generic helper method I use for ExecuteScalar. A helper method for ExecuteScalar is the perfect candidate for generics due to the different types that could be returned. Of course, you could always return an object, but this is more fun. :)
public
static
T ExecuteScalar(
string
commandText,
string
connectionString)
{
return
ExecuteScalar(commandText, connectionString,
null
);
}
public
static
T ExecuteScalar(
string
commandText,
string
connectionString,
params
SqlParameter
[] parameters)
{
T result =
default
(T);
if
(!
string
.IsNullOrEmpty(commandText))
{
using
(
SqlConnection
connection =
new
SqlConnection
(connectionString))
{
using
(
SqlCommand
command =
new
SqlCommand
(commandText, connection))
{
if
(parameters !=
null
&& parameters.Length > 0)
{
foreach
(
SqlParameter
parameter
in
parameters)
{
command.Parameters.Add(parameter);
}
}
connection.Open();
result = (T)command.ExecuteScalar();
connection.Close();
}
}
}
return
result;
}
Group
(
Of
Experts)
Generics is one of the most noted changes to the .NET Framework 2.0. Generics will reduce overhead due to boxing/unboxing
and the amount of errors in your code
. Want to learn about .NET Generics but don't know where to start? Join
StrongTypes
and get your questions answered by our Group Of Experts. No question is too tough. We will make it easy for you to learn Generics in hours, not days.
=> Join our
Group Of Experts
=> Find
articles and tutorials
=> Learn about
Generic collections
=> Read an
extensive introduction
=> Read about the
pros and cons
What are you waiting for? Join our
Group Of Experts
today.
Today I answered a thread regarding using generics with XML and it reminded me of the following blog entry regarding XML generics in .NET 3.0:
XML Generics
I answered a post on the ASP.NET forums where somebody was having problems with Generics and class inheritence. I ended up cooking this up as an example based upon what they had already provided in the thread.
using
System;
using
System.Collections.Generic;
public
abstract
class
BaseClass
{ }
public
class
ClassA
:
BaseClass
{ }
public
class
ClassB
:
ClassA
{ }
public
class
GenericClass
:
ClassB
{ }
public
class
NonInheritingClass
where
T :
BaseClass
{
private
List
<
GenericClass
> m_list;
public
virtual
int
AddToList(
GenericClass
baseObject)
{
if
(
this
.m_list ==
null
)
{
this
.m_list =
new
List
<
GenericClass
>();
}
this
.m_list.Add(baseObject);
return
m_list.Count;
}
}
public
class
SomeClass
{
public
static
int
TestMethod()
{
int
count;
NonInheritingClass
<
ClassB
> nonInheritingClass =
new
NonInheritingClass
<
ClassB
>();
GenericClass
<
ClassB
> classB =
new
GenericClass
<
ClassB
>();
count = nonInheritingClass.AddToList(classB);
return
count;
}
}
I just answered a thread where somebody wanted to know how to take any nullable type, check if it's value is null, and depending on that either return String.Empty or ToString. Here's how you do that:
public
static
string
ConvertNullableToString(T? value)
where
T :
struct
{
return
value.ToString() ??
String
.Empty;
}
int
? value1 =
null
;
int
? value2 = 9;
string
stringValue1 = ConvertNullableToString<
int
>(value1);
string
stringValue2 = ConvertNullableToString<
int
>(value2);
Earlier today I answered a question on a group where some guy was trying to use nullable types with a typed DataSet. Unfortunately, this feature was cut out at the last moment. But, there is a way around this.
Adding Functionality to a Typed DataSet using Partial Classes
I put together sample code that will run on the Northwind database that demonstrates using a generic List collection as a data source for an ObjectDataSource which populates a GridView control. All you have to do is specify the connection string in Web.config and the sample code will run. Enjoy.
Download C# ObjectDataSource Sample
Download VB.NET ObjectDataSource Sample
Using String.Format you can format any string. However, the last parameter that String.Format accepts is of type object. So, to add some type-safety to the mix, the following function works perfectly.
VB.NET
Public Function
FormatString(
Of
T)(
ByVal
originalString
As String
,
ByVal
replacement
As
T)
As String
Return String
.Format(originalString, replacement)
End Function
C#
public string
FormatString(
string
originalString, T replacement)
{
return
String
.Format(originalString, replacement);
}
Let's say for instance, you want to create a List of your own class, say Employee, where Employee represents an employee. First, we'll start by creating an employee class.
[
Serializable
]
public class
Employee
{
private bool
m_IsSalaried;
private int
m_Age;
private string
m_Email;
private string
m_Name;
public
Employee(
bool
isSalaried,
int
age,
string
email,
string
name)
{
m_Age = age;
m_Email = email;
m_IsSalaried = isSalaried;
m_Name = name;
}
public int
Age
{
get
{
return
m_Age; }
set
{ m_Age =
value
; }
}
public string
Email
{
get
{
return
m_Email; }
set
{ m_Email =
value
; }
}
public bool
IsSalaried
{
get
{
return
m_IsSalaried; }
set
{ m_IsSalaried =
value
; }
}
public string
Name
{
get
{
return
m_Name; }
set
{ m_Name =
value
; }
}
}
You can then add an employee to a List collection as follows:
using
System.Collections.Generic;
...
List
<
Employee
> m_EmployeeList =
new
List
<
Employee
>();
m_EmployeeList.Add(
new
Employee
(
true
, 30,
,
"Jane Doe"
));
You can get values for Employees in the List collection by enumerating through the Employees.
foreach
(
Employee
employee
in
m_EmployeeList)
{
SomeBool = employee.IsRetired;
SomeInt = employee.Age;
SomeString1 = employee.Email;
SomeString2 = employee.Name;
}
I was surfing the Internet today and came across David Wheeler's blog, which has some interesting entries on Generics.
Anonymous methods and handling events in .NET 2.0
Generics: An introduction
Generics: More advanced concepts
New and improved events
Take the following code, for example:
VB.NET
Public Class
TestClass(
Of
T)
End Class
Response.Write(GetType(TestClass(
Of Integer
)))
C#
public class
TestClass
{ }
Response.Write(
typeof
(
TestClass
<
int
>));
The above code results in the following output: TestClass`1[System.Int32]. The ` next to 1 indicates the arity of the generic class and the 1 after ` means it has an arity of 1. Arity is a term that refers to the number of type parameters used to construct a type.
Q:
What's wrong with the below generic class?
VB.NET
Imports
System.Data
Imports
System.Web
Public
Class
GenericClass(
Of
T
As
DataTable)
Public
Function
GetValue(
ByVal
val
As
T)
As
T
Return
val
End
Function
Public
Function
GetValue(
ByVal
val
As
T)
As
DataTable
Return
val
End
Function
Public
Sub
GetValue(
ByVal
val
As
T)
HttpContext.Current.Response.Write(val)
End
Sub
End
Class
C#
using
System.Data;
using
System.Web;
public
class
GenericClass
where
T :
DataTable
{
public
T GetValue(T val)
{
return
val;
}
public
DataTable
GetValue(T val)
{
return
val;
}
public
void
GetValue(T val)
{
HttpContext
.Current.Response.Write(val);
}
}
A:
At first glance, the overloaded methods appear to be unique. However, this is not the case. In VB.NET, the first 2 methods would error and in C# the last 2 methods would error. Why does this happen? Like non-generic methods, your generic methods must be unique by their method signatures, not just by their return types.
In generics, you can use sub classes just as you would any non-generic sub class. Take the following class and sub class for example:
VB.NET
Public Class
OuterClass(
Of
T, U, V)
Public Class
InnerClass(
Of
T, U)
Public Function
InnerMethod(
ByVal
val1
As
T,
ByVal
val2
As
U)
As
V
' Some code here
End Function
End Class
End Class
C#
public class
OuterClass
{
public class
InnerClass
{
public
V InnerMethod(T val1, U val2)
{
// Some code here
}
}
}
The above code is perfectly legal and will compile. The question is which class will T and U in InnerMethod inherit its type references from? The answer is the class which the method is contained in, in the case of the example provided above, InnerClass. However, you should never name the types of a sub class the same as those of the class it is contained in. If you get in the habbit of using strongly named types, you will avoid possible future problems.
One of the weirder features in C# 2.0 is nullable types. My thinking is as follows: Why complicate things with Nullable, or its shorter version of DataType? (i.e. int?), instead of allowing null values to be assigned to those data types that don't have any way of handling null? Maybe it was a matter of not breaking the framework or introducing changes gradually. Also, code such as that below will cause the compiler to error as nullable types and their non-nullable type equivelent are treated as 2 different types.
int
? m_Value1;
// The shorter version of Nullable m_Value1
m_Value1 =
int
.Parse(Request.QueryString[
"SomeNumberParam"
]);
int
m_Value2;
if
(m_Value1 !=
null
)
// Nullable types can be checked for null
{
m_Value2 = m_Value1;
// Won't compile
m_Value2 = (
int
)m_Value1;
// Will compile
}
Hopefully, in the next version of C#, nullable types will be replaced with the ability for their non-nullable versions to handle null, like below:
int
m_Value1, m_Value2;
m_Value1 =
int
.Parse(Request.QueryString[
"SomeNumberParam"
]);
if
(m_Value1 !=
null
)
{
m_Value2 = m_Value1;
}
Do you dare ask what this non-sense looks like in code form? In case you are wondering, I'm using the non-nullable form of the word form. Sorry if I've confused you by including the ? after form in order to form a question. I now present you with non-sense:
using
System;
using
System.Runtime.CompilerServices;
using
System.Runtime.InteropServices;
[
Serializable
,
StructLayout
(
LayoutKind
.Sequential),
TypeDependency
(
"System.Collections.Generic.NullableComparer`1"
),
TypeDependency
(
"System.Collections.Generic.NullableEqualityComparer`1"
)]
public
struct
Nullable
where
T :
struct
{
private
bool
hasValue;
internal
T value;
public
Nullable(T value)
{
this
.value = value;
this
.hasValue =
true
;
}
public
bool
HasValue
{
get
{
return
this
.hasValue;
}
}
public
T Value
{
get
{
if
(!
this
.HasValue)
{
ThrowHelper
.ThrowInvalidOperationException(
ExceptionResource
.InvalidOperation_NoValue);
}
return
this
.value;
}
}
public
T GetValueOrDefault()
{
return
this
.value;
}
public
T GetValueOrDefault(T defaultValue)
{
if
(!
this
.HasValue)
{
return
defaultValue;
}
return
this
.value;
}
public
override
bool
Equals(
object
other)
{
if
(!
this
.HasValue)
{
return
(other ==
null
);
}
if
(other ==
null
)
{
return
false
;
}
return
this
.value.Equals(other);
}
public
override
int
GetHashCode()
{
if
(!
this
.HasValue)
{
return
0;
}
return
this
.value.GetHashCode();
}
public
override
string
ToString()
{
if
(!
this
.HasValue)
{
return
""
;
}
return
this
.value.ToString();
}
public
static
explicit
operator
T(
Nullable
value)
{
return
value.get_Value();
}
public
static
implicit
operator
Nullable
(T value)
{
return
new
Nullable
(value);
}
}
One of the cooler features I like in Generics is type inference. Type inference allows you to call a generic method just as you would a non-generic method using its method signatures as references to the type(s), instead of specifying the type(s).
VB.NET
Public Sub
TestMethod1(
Of
T, U)(
ByVal
val1
As
T,
ByVal
val2
As
U)
Response.Write(
"Value 1: {0}, Value 2: {1}"
, val1, val2)
End Sub
Public Function
TestMethod2(
Of
T)(
ByVal
val
As
T)
As
T
Return
val
End Function
TestMethod1(
"Bob"
, 172)
' Same as TestMethod1(Of String, Integer)("Bob", 172)
TestMethod1(14,
"Marry"
)
' Same as TestMethod1(Of Integer, String)(14, "Marry")
TestMethod2(46)
' Same as TestMethod2(Of Integer)(46)
C#
public void
TestMethod1(T val1, U val2)
{
Response.Write(
"Value 1: {0}, Value 2: {1}"
, val1, val2);
}
public
T TestMethod2(T val)
{
return
val;
}
TestMethod1(
"Bob"
, 172);
// Same as TestMethod1("Bob", 172)
TestMethod1(14,
"Marry"
);
// Same as TestMethod1(14, "Marry")
TestMethod2(46);
// Same as TestMethod2(46)
More Posts
Next page »