Newbie question on creating class based on Int32

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I can't believe I can't find anything on this and feel free to publicly
humiliate me as long as you can provide an answer. I need to create a class
that looks and acts like an Int32 with additional functionality.

For example it should default to -1 and prevent negative values < -1, have a
HasDefaultValue property that returns true if it is still -1, etc. It should
also accept assignment using = rather than having to use var.Value = 1. It
should be a transparent replacement for Int32 (int) with additional
functionality.

I’m not looking for a complete source code example, but I assume there is a
pre-existing resource out there on the web somewhere in the form of a
tutorial or C# 101 example.

Thanks in advance for any help you can provide.
 
Just FYI, in 2.0 you can use a generics class called "Nullable" that may provide some of what you are looking for.

Here's a 1.1 solution that I've tested to ensure that it works correctly:

(Not all Int32 functionality is present. Many operator overloads are neseccary but you can implement them if you want, and you'd
have to implement IConvertible, although the Int32 IConvertible implementation just calls Convert.To* anyway. If you want it to
work nicely with VB.NET you should add a method for each operator overload such as "Add", etc.)


/// <summary>
/// Psuedo-<see cref="Int32" /> that provides a default value of <c>-1</c> and does
/// not allow implicit or explicit conversion from or to <c>System.Int32</c> of values
/// less than <c>-1</c>.
/// </summary>
public struct Int32Ext
{
public bool IsDefault
{
get { return !userSet; }
}


private bool userSet;
private int val;

public Int32Ext(int value)
{
val = value;
userSet = value != -1;
}


public static implicit operator Int32Ext(int value)
{
Int32Ext i = new Int32Ext();

if (value < -1)
throw new ArgumentOutOfRangeException("Int32", value, "Int32Ext cannot not be less than -1");
else if (value != -1)
i.userSet = true;

i.val = value;
return i;
}


public static implicit operator int(Int32Ext value)
{
return value.val;
}


public override bool Equals(object obj)
{
return (!userSet) ? (-1).Equals(obj) : val.Equals(obj);
}


public override int GetHashCode()
{
return (!userSet) ? -1.GetHashCode() : val.GetHashCode();
}


public override string ToString()
{
return (!userSet) ? "-1" : val.ToString();
}
}


public static void Main()
{
Console.WriteLine("4 Examples: ");
Console.WriteLine();

Int32Ext i = 4;
Int32Ext i2 = -1;

Console.Write("Int32Ext i = ");
Console.WriteLine(i);
Console.WriteLine("IsDefault = {0}", i.IsDefault);

Console.Write("i2 = ");
Console.WriteLine(Int32Ext i2);
Console.WriteLine("IsDefault = {0}", i2.IsDefault);

Int32Ext i3 = new Int32Ext();

try
{
i3 = -4;
}
catch (Exception ex)
{
Console.WriteLine("Error setting i3 to -4:");
Console.WriteLine();
Console.WriteLine(ex.Message);
Console.WriteLine();
}

Console.Write("Int32Ext i3 = ");
Console.WriteLine(i3);
Console.WriteLine("IsDefault = {0}", i3.IsDefault);
Console.WriteLine();

Int32Ext i4 = new Int32Ext(40);
int int4 = i4;

Console.Write("int int4 = ");
Console.WriteLine(int4);
Console.WriteLine();
}


(Main) produces the following output:

4 Examples:

i = 4
IsDefault = False
i2 = -1
IsDefault = True
Error setting i3 to -4:

Int32Ext cannot not be less than -1
Parameter name: Int32
Actual value was -4.

i3 = 0
IsDefault = True

int4 = 40

Press any key to continue
 
Byron said:
I can't believe I can't find anything on this and feel free to publicly
humiliate me as long as you can provide an answer. I need to create a class
that looks and acts like an Int32 with additional functionality.

Well, to what purpose do you need the class? what's wrong with uint?
For example it should default to -1 and prevent negative values < -1, have a
HasDefaultValue property that returns true if it is still -1, etc.

You can name one of the bit-patterns of uint as the default, I recommend
~0, which, accidentally, is the same bit-patterns as (int)-1 ;)

HasDefaultValue is simply a "x == ~0" and you can prevent assignments of
the default-value if you like.
It should
also accept assignment using = rather than having to use var.Value = 1. It
should be a transparent replacement for Int32 (int) with additional
functionality.

You can't override operator= in C#.
I’m not looking for a complete source code example, but I assume there is a
pre-existing resource out there on the web somewhere in the form of a
tutorial or C# 101 example.

It is rather complicated to make a replacement for the .NET built-in
types with a default different from the default of the components.
Especially for array's, since structs cannot have explicit parameterless
constructors.

Additionally, there is really no way you are going to be able to make
the replacement class transparently convert from int/uint/...
 
Maybe I was too literal about the transparent replacement. I don't want to
come up with my own class named int, but I want a class that I could replace
int with that "looks and feels" like an int type so I could replace all int i
= 0 with myInt i = 0, etc. without the application breaking.

For instance:

int i = 1;
myInt j = 2;

(i == j) = false;
((i + 1) == j) = true;

i = j results in (i == 2)

I want to avoid things like:

j.Value = 2;
and
i = Convert.ToInt32(j);
 
Byron said:
Maybe I was too literal about the transparent replacement. I don't want to
come up with my own class named int, but I want a class that I could replace
int with that "looks and feels" like an int type so I could replace all int i
= 0 with myInt i = 0, etc. without the application breaking.

For instance:

int i = 1;
myInt j = 2;

(i == j) = false;
((i + 1) == j) = true;

i = j results in (i == 2)

I want to avoid things like:

j.Value = 2;
and
i = Convert.ToInt32(j);

You could do all of that with implicit conversion operators. I'm not
sure I'd usually recommend it though - or calling int/Int32 (which are
well-known names) by less well-known names.
 
Maybe I’m trying to solve a problem that doesn’t exist. I do mostly database
apps that use primarily positive integer primary key columns. In my classes
the ID is defaulted to -1 and the database insert stored procedures set and
return the ID. This means that any class with -1 as the ID are new records
that did not come from the database. In most other cases class values have
default values such as -1.0m for decimals and blank string for string values.

When I validate the class prior to committing it to the database I can check
the values to make sure that those that are required have a value other than
their default and fail the validation if that is the case. In the case of
values that are not required for the database, but whose columns in the table
allow NULL, I set the parameter to NULL in place of the default class value.
For instance an optional int database column would receive NULL if the class
value was still at the default value of -1.

Right now I’m using the native C# data types and use properties in the
classes such as IsNew that returns (ID == -1). I thought it would be cleaner
to create a new class that would replace int that would check for ID value ==
-1, or > 0 and would have its own IsNew and IsChanged (has something other
than its default value) rather than using the -1 literal through the code and
putting the IsNew and IsChanged properties in every class that now uses int
datatype.

Right now my classes all have something like (this was typed off the top of
my head, don't expect perfect syntax):

int id = -1;

public int ID
{
set{this.id = value;}
get{return this.id;}
}

public bool IsNew
{
get{return this.id == -1;}
}

Would it be better to have:

myInt id; (where myInt is an int class with the properties now in the class.)

myInt would have

public bool IsNew
{
get{return this.id == DefaultID;}
}

Where DefaultID is a constant.

The class IsNew would then be

public IsNew
{
get{return this.id.IsNew;}
}

What do most people do with this? I have classes that all have integer IDs,
UInt64 timestamps, required string names, an IsDirty and IsNew property and
such.
 
Byron said:
Maybe I'm trying to solve a problem that doesn't exist. I do mostly
database
apps that use primarily positive integer primary key columns. In my
classes
the ID is defaulted to -1 and the database insert stored procedures set
and
return the ID. This means that any class with -1 as the ID are new
records
that did not come from the database. In most other cases class values
have
default values such as -1.0m for decimals and blank string for string
values.

Not saying that you should/should not use datasets, but you may want to look
into the way that they handle identity keys.

They assign incrementing negative numbers to each new row so that each row
can be uniquely indentified and used as a foreign key for new rows in
related tables that have not been posted to the database yet.
 
Back
Top