By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,247 Members | 1,224 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,247 IT Pros & Developers. It's quick & easy.

Abstract class variables question

P: n/a
Using VS 2003, I am trying to take a class that I created to create new
variable types to handle nulls and track changes to standard variable types.
This is for use with database variables. This tells me if a variable has
changed, give me the original and current value, and whether the current
value and original value is/was null or not.

This one works fine but is recreating the same methods over and over for
each variable type.

What I wanted to do was create an Abstract class that did most of the work
and create a class for each variable type that only does what is needed.

I can't seem to get it to work correctly.

Part of it has to do with where to define my actual data variables. I tried
defining them only as objects in the abstract class but that won't work
because the class doesn't know what type of object it is.

The original file (with most variable types cut out is):
******************************************
using System;
using System.IO;

namespace FtsData
{
[Serializable]
public class StringType
{
private string first = ""; //original data
private string data = ""; //current data
private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

public StringType()
{
}
public StringType(string initial)
{
first = initial;
data = initial;
}

public bool IsNull()
{
return nullData;
}

public bool IsFirstNull()
{
return nullFirst;
}

public void SetNull()
{
nullData = true;
data = "";
}

public void SetFirstNull()
{
nullFirst = true;
first = "";
}

// Properties

public string First
{
get { return first; }
set { first = value; }
}

public string Data
{
get { return data; }
set { data = value; nullData = false; changed = true;}
}

public bool Changed
{
get {return changed;}
set {changed = value;}
}
} // end Class

[Serializable]
public class BoolType
{
private bool first = false; //original data
private bool data = false; //current data
private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

public BoolType()
{
}

public BoolType(bool initial)
{
first = initial;
data = initial;
changed = false;
}

public bool IsNull()
{
return nullData;
}

public bool IsFirstNull()
{
return nullFirst;
}

public void SetNull()
{
nullData = true;
data = false;
}

public void SetFirstNull()
{
nullFirst = true;
data = false;
}

// Properties

public bool First
{
get { return first; }
set { first = value; }
}

public bool Data
{
get { return data; }
set { data = value; nullData = false; changed = true;}
}

public bool Changed
{
get {return changed;}
set {changed = value;}
}
} // end Class
} // end Namespace

*******************************************

As you can see much if it is identical and can just be done as an object -
but some can't.

I tried this but did get some errors:
*******************************************
using System;
using System.IO;

namespace FtsData
{
public abstract class DataType
{
protected object _first;
protected object _data;
private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

public bool IsNull()
{
return nullData;
}

public bool IsFirstNull()
{
return nullFirst;
}

public void SetNull()
{
nullData = true;
_data = "";
}

public void SetFirstNull()
{
nullFirst = true;
_first = "";
}
// Properties

public string First
{
get { return _first; }
set { _first = value; }
}

public string Data
{
get { return _data; }
set { _data = value; nullData = false; changed = true;}
}

public bool Changed
{
get {return changed;}
set {changed = value;}
}
}

[Serializable]
public class StringType : DataType
{
private string _first = ""; //original data
private string _data = ""; //current data

public StringType()
{
}
public StringType(string initial)
{
_first = initial;
_data = initial;
changed = false;
}

} // end Class

[Serializable]
public class BoolType : DataType
{
private bool _first = false; //original data
private bool _data = false; //current data

public BoolType()
{
}

public BoolType(bool initial)
{
_first = initial;
_data = initial;
changed = false;
}
} // end Class

} // end namespace
********************************************

I assume I need to create the variables in each class (StringType, BoolType,
IntegerType, DecimalType etc).

I also assume that anything that actually needs to explicitly change the
variables to some value, such as strings to "" or bool to false.
I assume I can't access these variables from my Abstract Class definitions.
This is why I was trying to create them as objects, but then they are
separate variables and I would like to do this only one time. But I can't
seem to figure out how to make that work. So the following may also have to
go each class.

public void SetNull()
{
nullData = true;
_data = "";
}

It's possible I may only be able to handle these from the abstract classes:

private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

But I am just trying to find out if I am overlooking something. I am trying
to get this to simplest set of class that I can.

Thanks,

Tom
Nov 14 '07 #1
Share this Question
Share on Google+
20 Replies


P: n/a
The obvious answer is to switch over to Visual Studio 2005, and .Net 2.0.

The newer version of .Net has deep support of Nullable types, for exactly
the reason you laid out.
http://blogs.msdn.com/ericgu/archive...27/143221.aspx

There is qutie a bit of material on this available on the web.

If you can't use .Net 2.0, write back, and hopefully we can figure something
out...

--
Chris Mullins

"tshad" <tf*@dslextreme.comwrote in message
news:Og**************@TK2MSFTNGP02.phx.gbl...
Using VS 2003, I am trying to take a class that I created to create new
variable types to handle nulls and track changes to standard variable
types. This is for use with database variables. This tells me if a
variable has changed, give me the original and current value, and whether
the current value and original value is/was null or not.

This one works fine but is recreating the same methods over and over for
each variable type.

What I wanted to do was create an Abstract class that did most of the work
and create a class for each variable type that only does what is needed.

I can't seem to get it to work correctly.

Part of it has to do with where to define my actual data variables. I
tried defining them only as objects in the abstract class but that won't
work because the class doesn't know what type of object it is.

The original file (with most variable types cut out is):
******************************************
using System;
using System.IO;

namespace FtsData
{
[Serializable]
public class StringType
{
private string first = ""; //original data
private string data = ""; //current data
private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

public StringType()
{
}
public StringType(string initial)
{
first = initial;
data = initial;
}

public bool IsNull()
{
return nullData;
}

public bool IsFirstNull()
{
return nullFirst;
}

public void SetNull()
{
nullData = true;
data = "";
}

public void SetFirstNull()
{
nullFirst = true;
first = "";
}

// Properties

public string First
{
get { return first; }
set { first = value; }
}

public string Data
{
get { return data; }
set { data = value; nullData = false; changed = true;}
}

public bool Changed
{
get {return changed;}
set {changed = value;}
}
} // end Class

[Serializable]
public class BoolType
{
private bool first = false; //original data
private bool data = false; //current data
private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

public BoolType()
{
}

public BoolType(bool initial)
{
first = initial;
data = initial;
changed = false;
}

public bool IsNull()
{
return nullData;
}

public bool IsFirstNull()
{
return nullFirst;
}

public void SetNull()
{
nullData = true;
data = false;
}

public void SetFirstNull()
{
nullFirst = true;
data = false;
}

// Properties

public bool First
{
get { return first; }
set { first = value; }
}

public bool Data
{
get { return data; }
set { data = value; nullData = false; changed = true;}
}

public bool Changed
{
get {return changed;}
set {changed = value;}
}
} // end Class
} // end Namespace

*******************************************

As you can see much if it is identical and can just be done as an object -
but some can't.

I tried this but did get some errors:
*******************************************
using System;
using System.IO;

namespace FtsData
{
public abstract class DataType
{
protected object _first;
protected object _data;
private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

public bool IsNull()
{
return nullData;
}

public bool IsFirstNull()
{
return nullFirst;
}

public void SetNull()
{
nullData = true;
_data = "";
}

public void SetFirstNull()
{
nullFirst = true;
_first = "";
}
// Properties

public string First
{
get { return _first; }
set { _first = value; }
}

public string Data
{
get { return _data; }
set { _data = value; nullData = false; changed = true;}
}

public bool Changed
{
get {return changed;}
set {changed = value;}
}
}

[Serializable]
public class StringType : DataType
{
private string _first = ""; //original data
private string _data = ""; //current data

public StringType()
{
}
public StringType(string initial)
{
_first = initial;
_data = initial;
changed = false;
}

} // end Class

[Serializable]
public class BoolType : DataType
{
private bool _first = false; //original data
private bool _data = false; //current data

public BoolType()
{
}

public BoolType(bool initial)
{
_first = initial;
_data = initial;
changed = false;
}
} // end Class

} // end namespace
********************************************

I assume I need to create the variables in each class (StringType,
BoolType, IntegerType, DecimalType etc).

I also assume that anything that actually needs to explicitly change the
variables to some value, such as strings to "" or bool to false.
I assume I can't access these variables from my Abstract Class
definitions. This is why I was trying to create them as objects, but then
they are separate variables and I would like to do this only one time.
But I can't seem to figure out how to make that work. So the following
may also have to go each class.

public void SetNull()
{
nullData = true;
_data = "";
}

It's possible I may only be able to handle these from the abstract
classes:

private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

But I am just trying to find out if I am overlooking something. I am
trying to get this to simplest set of class that I can.

Thanks,

Tom

Nov 14 '07 #2

P: n/a
"Chris Mullins [MVP - C#]" <cm******@yahoo.comwrote in message
news:ej**************@TK2MSFTNGP06.phx.gbl...
The obvious answer is to switch over to Visual Studio 2005, and .Net 2.0.

The newer version of .Net has deep support of Nullable types, for exactly
the reason you laid out.
http://blogs.msdn.com/ericgu/archive...27/143221.aspx

There is qutie a bit of material on this available on the web.

If you can't use .Net 2.0, write back, and hopefully we can figure
something out...
I can't go to 2.0. I am looking forward to going to it, but at the moment I
can't. I would still have the same problem as handling the null variables
are not a problem. The (_first and _data) are the real problems.

Also, I am trying to understand Abstract Classes better and this seemed like
a pretty set of classes that I already had working to start with. I would
like to Abstract to simplify my classes as well as make them easier to
maintain.

Thanks,

Tom
>
--
Chris Mullins

"tshad" <tf*@dslextreme.comwrote in message
news:Og**************@TK2MSFTNGP02.phx.gbl...
>Using VS 2003, I am trying to take a class that I created to create new
variable types to handle nulls and track changes to standard variable
types. This is for use with database variables. This tells me if a
variable has changed, give me the original and current value, and
whether the current value and original value is/was null or not.

This one works fine but is recreating the same methods over and over for
each variable type.

What I wanted to do was create an Abstract class that did most of the
work and create a class for each variable type that only does what is
needed.

I can't seem to get it to work correctly.

Part of it has to do with where to define my actual data variables. I
tried defining them only as objects in the abstract class but that won't
work because the class doesn't know what type of object it is.

The original file (with most variable types cut out is):
******************************************
using System;
using System.IO;

namespace FtsData
{
[Serializable]
public class StringType
{
private string first = ""; //original data
private string data = ""; //current data
private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

public StringType()
{
}
public StringType(string initial)
{
first = initial;
data = initial;
}

public bool IsNull()
{
return nullData;
}

public bool IsFirstNull()
{
return nullFirst;
}

public void SetNull()
{
nullData = true;
data = "";
}

public void SetFirstNull()
{
nullFirst = true;
first = "";
}

// Properties

public string First
{
get { return first; }
set { first = value; }
}

public string Data
{
get { return data; }
set { data = value; nullData = false; changed = true;}
}

public bool Changed
{
get {return changed;}
set {changed = value;}
}
} // end Class

[Serializable]
public class BoolType
{
private bool first = false; //original data
private bool data = false; //current data
private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

public BoolType()
{
}

public BoolType(bool initial)
{
first = initial;
data = initial;
changed = false;
}

public bool IsNull()
{
return nullData;
}

public bool IsFirstNull()
{
return nullFirst;
}

public void SetNull()
{
nullData = true;
data = false;
}

public void SetFirstNull()
{
nullFirst = true;
data = false;
}

// Properties

public bool First
{
get { return first; }
set { first = value; }
}

public bool Data
{
get { return data; }
set { data = value; nullData = false; changed = true;}
}

public bool Changed
{
get {return changed;}
set {changed = value;}
}
} // end Class
} // end Namespace

*******************************************

As you can see much if it is identical and can just be done as an
object - but some can't.

I tried this but did get some errors:
*******************************************
using System;
using System.IO;

namespace FtsData
{
public abstract class DataType
{
protected object _first;
protected object _data;
private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

public bool IsNull()
{
return nullData;
}

public bool IsFirstNull()
{
return nullFirst;
}

public void SetNull()
{
nullData = true;
_data = "";
}

public void SetFirstNull()
{
nullFirst = true;
_first = "";
}
// Properties

public string First
{
get { return _first; }
set { _first = value; }
}

public string Data
{
get { return _data; }
set { _data = value; nullData = false; changed = true;}
}

public bool Changed
{
get {return changed;}
set {changed = value;}
}
}

[Serializable]
public class StringType : DataType
{
private string _first = ""; //original data
private string _data = ""; //current data

public StringType()
{
}
public StringType(string initial)
{
_first = initial;
_data = initial;
changed = false;
}

} // end Class

[Serializable]
public class BoolType : DataType
{
private bool _first = false; //original data
private bool _data = false; //current data

public BoolType()
{
}

public BoolType(bool initial)
{
_first = initial;
_data = initial;
changed = false;
}
} // end Class

} // end namespace
********************************************

I assume I need to create the variables in each class (StringType,
BoolType, IntegerType, DecimalType etc).

I also assume that anything that actually needs to explicitly change the
variables to some value, such as strings to "" or bool to false.
I assume I can't access these variables from my Abstract Class
definitions. This is why I was trying to create them as objects, but then
they are separate variables and I would like to do this only one time.
But I can't seem to figure out how to make that work. So the following
may also have to go each class.

public void SetNull()
{
nullData = true;
_data = "";
}

It's possible I may only be able to handle these from the abstract
classes:

private bool nullFirst = false; //original Data null
private bool nullData = false; //current data null
private bool changed = false;

But I am just trying to find out if I am overlooking something. I am
trying to get this to simplest set of class that I can.

Thanks,

Tom


Nov 14 '07 #3

P: n/a
On 2007-11-13 20:00:20 -0800, Peter Duniho <Np*********@NnOwSlPiAnMk.comsaid:
[...]
That said, it seems to me that something like this would at least
approach what you're trying to do:
Sorry...I appear to have left out the constructors. :( Oh
well...hopefully you get the idea and can add that yourself. It
shouldn't be too much of an inconvenience.

Nov 14 '07 #4

P: n/a
On 2007-11-13 22:42:29 -0800, "tshad" <tf*@dslextreme.comsaid:
This looks pretty much like what I am trying to do.

I hadn't thought about using the objects as null instead of using a separate
variable for it.

I did get an error below when working with it:

abstract protected Type _TypeRequired;

gave me an error:

The modifier 'abstract' is not valid for this item
Sorry. That's what I (you) get for me just typing in code without
trying it. :)

The proper declaration would be:

abstract protected Type _TypeRequired { get; }

Also, you'll need "override" with the declarations of that property in
the concrete types.
Not sure why that is.
'Cause I need a compiler to keep me honest. :)
As far as the constructors - I assume I need to set them for each class
Yes.
[...]
This was the problem I was having before where I have no way of knowing what
type the object is - not sure if it is really a problem however.

In the 2nd constructor, I am setting the object to a type (since that is
defined in the parameter). But what about the first constructor where I am
not passing anything.
You would use that constructor if the initial value is to be null. But
the concrete type still defines the actual type. So if you're using
the BoolType() constructor, that is only found in the BoolType class,
and the type of the data is bool. Etc.

It's the data class that defines the type, not whatever value you pass
to it in the constructor.
Therefore, the object is not pointing at any variable.
There's no (practical) way to have an object point to a variable. It
can only point to an instance of some data. It's true that when the
data is null, the object points to null and no actual data. But again,
the concrete class has a specific type and that specific type is what
provides type information about the data, even when it's null.

Pete

Nov 14 '07 #5

P: n/a
"Peter Duniho" <Np*********@NnOwSlPiAnMk.comwrote in message
news:2007111400001816807-NpOeStPeAdM@NnOwSlPiAnMkcom...
On 2007-11-13 22:42:29 -0800, "tshad" <tf*@dslextreme.comsaid:
Also, you'll need "override" with the declarations of that property in the
concrete types.
That fixed it.

I made some changes and agree that I don't need SetNull methods or the
setters for some of the Properties.

I did need to add a method Reset() to reset the _objInitial variable to be
whatever the _objCurrent is at the time as well as change the _fChange to
false.

This is to handle the situations, such as Database updates or inserts, where
we still want to use the same screen but have already updated the data. At
that point, I don't care what the original data was, since the record(s)
have been updated and I now want the current data to match the original data
so I can tell if the data changed so that I can update the records again if
necessary.

I did find that the methods:

// A convenience method so that no casting is needed when you already have
// a fully typed object
public bool TypedData
{
get { return (bool)Data; }
set { Data = value; }
}

doesn't seem to work.

Actually, it compiles fine. But the problem is that the compiler won't let
me do the following in my code that calls these objects:

bool test;
BoolType booltemp = new BoolType(false);
booltemp.Data = true;
test = booltemp.Data;
test = booltemp.First;

I get an error on the last 2 lines.

Cannot implicitly convert type 'object' to 'bool'

I assume the method is supposed to handle that - but I don't think the
compiler sees the method.

Am I missing something?

Here is the code I am using at the moment:
**************************************
C:\VSProjects\DBTypesCSharp2\Form1.cs(93): using System;
using System.IO;

namespace FtsData
{
abstract class DataType
{
protected object _objInitial;
protected object _objCurrent;
private bool _fChanged;

public bool IsNull
{
get { return _objCurrent == null; }
}

public bool IsFirstNull
{
get { return _objInitial == null; }
}

// Reset _objInitial to _objCurrent and changed flag to false to track
// when this variable changes again. This would be necessary if were to
// write out data to a database record and need to track when it changes
again

public void Reset()
{
_objInitial = _objCurrent;
_fChanged = false;
}

public object First
{
get { return _objInitial; }
}

public object Data
{
get { return _objCurrent; }
set
{
if (value != null)
{
_ValidateType(value);
}
_objCurrent = value;
_fChanged = true;
}
}

// Likewise, I don't think Changed should include a setter
public bool Changed
{
get { return _fChanged; }
}

// This is what deriving classes will define so the type can be checked
abstract protected Type _TypeRequired { get; }

private void _ValidateType(object obj)
{
Type typeRequired = _TypeRequired;

// Depending on how you're using this class, you may instead prefer
// to check for exact type equality. The below simply requires that
// the passed-in object has the required type in its inheritance chain.

if (!typeRequired.IsInstanceOfType(obj))
{
throw new ArgumentException("assigned value type of " +
obj.GetType().Name + " is incompatible with required type of " +
typeRequired.Name);
}
}
}

class BoolType : DataType
{
public BoolType()
{
}

public BoolType(bool initial)
{
_objInitial= initial;
_objCurrent = initial;
}

// Each class defines this so that the base type can validate the data's
type
protected override Type _TypeRequired
{
get { return typeof(bool); }
}

// A convenience method so that no casting is needed when you already have
// a fully typed object
public bool TypedData
{
get { return (bool)Data; }
set { Data = value; }
}
}

class StringType : DataType
{
public StringType()
{
}

public StringType(bool initial)
{
_objInitial= initial;
_objCurrent = initial;
}

protected override Type _TypeRequired
{
get { return typeof(string); }
}

public string TypedData
{
get { return (string)Data; }
set { Data = value; }
}
}
}
**************************************

Thanks,

Tom
Nov 15 '07 #6

P: n/a
On 2007-11-14 22:16:31 -0800, "tshad" <tf*@dslextreme.comsaid:
[...]
I did need to add a method Reset() to reset the _objInitial variable to be
whatever the _objCurrent is at the time as well as change the _fChange to
false.

This is to handle the situations, such as Database updates or inserts, where
we still want to use the same screen but have already updated the data.
That's fine. The class is for your use. You should put the features
you need into it. :)
[...]
Actually, it compiles fine. But the problem is that the compiler won't let
me do the following in my code that calls these objects:

bool test;
BoolType booltemp = new BoolType(false);
booltemp.Data = true;
test = booltemp.Data;
test = booltemp.First;

I get an error on the last 2 lines.

Cannot implicitly convert type 'object' to 'bool'

I assume the method is supposed to handle that - but I don't think the
compiler sees the method.
No, the property I included as a convenience property (sorry for the
misleading comment that says "method" :) ) needs to be used directly
for it to be useful. It doesn't change how the base class properties
behave.

So in your code, you could write this:

test = booltemp.TypedData;

and that would work.

You can also add a similar property for the first value:

public bool TypedFirst
{
get { return (bool)Data; }
set { Data = value; }
}

Then the second of the two lines causing an error would look like:

test = booltemp.TypedFirst;

Note that strictly speaking, the setter for the typed property isn't
required, since the down-cast to Object works automatically with the
base class property. I like having it though, just for the symmetry.

Hope that helps.

Pete

Nov 15 '07 #7

P: n/a

"Peter Duniho" <Np*********@NnOwSlPiAnMk.comwrote in message
news:2007111415323916807-NpOeStPeAdM@NnOwSlPiAnMkcom...
On 2007-11-14 22:16:31 -0800, "tshad" <tf*@dslextreme.comsaid:
>[...]

No, the property I included as a convenience property (sorry for the
misleading comment that says "method" :) ) needs to be used directly for
it to be useful. It doesn't change how the base class properties behave.

So in your code, you could write this:

test = booltemp.TypedData;

and that would work.

You can also add a similar property for the first value:

public bool TypedFirst
{
get { return (bool)Data; }
set { Data = value; }
}
I assume this is supposed to be:

public bool TypedFirst
{
get { return (bool)First; }
set { First = value; }
}

Also, is there any reason you used First instead of _objInitial and Data
instead of _objCurrent? Or was it 6 of one half dozen...?

I am still trying to figure out what the following does. I assume this is a
property. Is there any reason why you need to abstract it?

// This is what deriving classes will define so the type can be checked
abstract protected Type _TypeRequired { get; }

Each of the classes could just do:

// Each class defines this so that the base type can validate the data's
type
protected Type _TypeRequired
{
get { return typeof(bool); }
}

Right?

Or is it to force code to have this in each class to avoid forgetting it?
>
Then the second of the two lines causing an error would look like:

test = booltemp.TypedFirst;

Note that strictly speaking, the setter for the typed property isn't
required, since the down-cast to Object works automatically with the base
class property. I like having it though, just for the symmetry.

Hope that helps.
It does a lot.

Learned a lot from this.

Thanks,

Tom
>
Pete

Nov 15 '07 #8

P: n/a
>No, they couldn't. The base class needs to know that this property
exists, because it uses it to validate the type when setting the data.
Without the abstract property, you couldn't write code in the base class
that relies on the property without having the base class be aware of
each and every derived class.

Which was what I was trying to figure out. And this is obviously the
answer as to how the Base Class can tell what the type is.

But I am confused as to how it works.

You actually set _TypeRequired in each class and _ValidateType seems to
know what _TypeRequired is. In _ValidateType, at the line:

Type typeRequired = _TypeRequired;

Before it is actually executed - it seems to know what _TypeRequired is
!!! Yet I can't see where it is actually being set - just defined (either
as abstract or overridden).
It's a property, not a variable, so it is computed each time it is
referenced by calling the getter. The getter is simply "{ return
typeof(bool); }".
Nov 15 '07 #9

P: n/a
On 2007-11-15 13:45:12 -0800, "tshad" <tf*@dslextreme.comsaid:
[...]
No, they couldn't. The base class needs to know that this property
>exists, because it uses it to validate the type when setting the data.
Without the abstract property, you couldn't write code in the base class
that relies on the property without having the base class be aware of each
and every derived class.

Which was what I was trying to figure out. And this is obviously the answer
as to how the Base Class can tell what the type is.

But I am confused as to how it works.

You actually set _TypeRequired in each class and _ValidateType seems to know
what _TypeRequired is. In _ValidateType, at the line:

Type typeRequired = _TypeRequired;

Before it is actually executed - it seems to know what _TypeRequired is !!!
That's probably just the debugger being clever. Nothing is actually
known until the getter for the property is executed, which doesn't
happen until that assignment is executed (or until the debugger tries
to evaluate the property).
Yet I can't see where it is actually being set - just defined (either as
abstract or overridden).

I added a line just to break on and see what _TypeRequired is and it knew it
was system.bool. But where did it get set???
It's "set" basically as a hard-coded statement in the property
declaration. There's no data storing the value; just a line of code
that always returns the same value.

Because the property is "abstract", it's basically a virtual property,
but without a default implementation (think pure virtual in C++). As a
virtual property, the base class can call it without knowing the
concrete type of the instance, and the override will still be executed
and return the right value.

But the value per se isn't initialized or stored anywhere.
[...]
Just out of curiosity - I was wondering why you underscore _ValidateType and
_TypeRequired. I understand why you do it for _objCurrent (memory variable)
and why you use prefix the type (obj - hungarian). But I was wondering
about the other 2.
Actually, you don't understand why I do it for _objCurrent. :)

I am in the habit of using the underscore prefix for non-public members
of classes. That's what you're seeing there. That applies both to
_objCurrent field as well as methods and properties (like _ValidateType
and _TypeRequired).

Pete

Nov 15 '07 #10

P: n/a
"Peter Duniho" <Np*********@NnOwSlPiAnMk.comwrote in message
news:2007111515214511272-NpOeStPeAdM@NnOwSlPiAnMkcom...
On 2007-11-15 13:45:12 -0800, "tshad" <tf*@dslextreme.comsaid:
>[...]
No, they couldn't. The base class needs to know that this property
>>exists, because it uses it to validate the type when setting the data.
Without the abstract property, you couldn't write code in the base class
that relies on the property without having the base class be aware of
each
and every derived class.

Which was what I was trying to figure out. And this is obviously the
answer
as to how the Base Class can tell what the type is.

But I am confused as to how it works.

You actually set _TypeRequired in each class and _ValidateType seems to
know
what _TypeRequired is. In _ValidateType, at the line:

Type typeRequired = _TypeRequired;

Before it is actually executed - it seems to know what _TypeRequired is
!!!

That's probably just the debugger being clever. Nothing is actually known
until the getter for the property is executed, which doesn't happen until
that assignment is executed (or until the debugger tries to evaluate the
property).
>Yet I can't see where it is actually being set - just defined (either as
abstract or overridden).

I added a line just to break on and see what _TypeRequired is and it knew
it
was system.bool. But where did it get set???

It's "set" basically as a hard-coded statement in the property
declaration. There's no data storing the value; just a line of code that
always returns the same value.
So the _TypeRequired is really nothing until the "get" which would be during
the assignment here:

Type typeRequired = _TypeRequired;

I assume that what happens when it gets to the this statement is that it
1) does the "get" on the _TypeRequired
2) Takes the returned value (system.boolean, system.string, system.integer
etc) and assignes it to typeRequired

And then when you actually do the assignment of Data, it doesn't really
matter what the type is as the object pointer is now pointing at:

public object Data
{
get { return _objCurrent; }
set
{
if (value != null)
{
_ValidateType(value);
}
_objCurrent = value;
_fChanged = true;
}
}

Since it would be something like:

bool temp;
BoolType boolTypeTemp = new BoolType();
boolTypeTemp.Data = true
temp = (bool)boolTypeTemp;

In the 3rd line, we are putting true into the object _objCurrent and
_objCurrent doesn't really care what it is. It is just an object. Of
course, before we actually assigned it we checked the type with
_ValidateType(value).

So now we have an object _objCurrent that is set to the value of true but
_objCurrent doesn't really know that it is a bool, just that it has a value
of true. Which, if I am not mistaken is just a place on the heap with a -1
one in it and _objCurrent is just a pointer to it. Correct?

And when I return it, I need to cast it to bool since we are just passing
back an object which could be anything.

Also, I assume that a null would be a problem if I tried to pass it back a
null. If I did this, I would have a problem since bool can't be null.
Right?

bool temp;
BoolType boolTypeTemp = new BoolType();
boolTypeTemp.Data = null
temp = (bool)boolTypeTemp;
Because the property is "abstract", it's basically a virtual property, but
without a default implementation (think pure virtual in C++). As a
virtual property, the base class can call it without knowing the concrete
type of the instance, and the override will still be executed and return
the right value.

But the value per se isn't initialized or stored anywhere.
>[...]
Just out of curiosity - I was wondering why you underscore _ValidateType
and
_TypeRequired. I understand why you do it for _objCurrent (memory
variable)
and why you use prefix the type (obj - hungarian). But I was wondering
about the other 2.

Actually, you don't understand why I do it for _objCurrent. :)

I am in the habit of using the underscore prefix for non-public members of
classes. That's what you're seeing there. That applies both to
_objCurrent field as well as methods and properties (like _ValidateType
and _TypeRequired).
I guess I didn't understand.

What I typically do is use camel case for my memory variables and Pascal
case for my objects, properties and functions.

Of course, this causes a problem in asp.net if I have a textbox named Name
and memory variable as name - now what do I do with my property. What I
typically do is at this point just change the textbox name to objName.

Not really very clean. I need to think it through better.

Thanks,

Tom
Nov 16 '07 #11

P: n/a
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:up**************@TK2MSFTNGP04.phx.gbl...
>
>>No, they couldn't. The base class needs to know that this property
exists, because it uses it to validate the type when setting the data.
Without the abstract property, you couldn't write code in the base class
that relies on the property without having the base class be aware of
each and every derived class.

Which was what I was trying to figure out. And this is obviously the
answer as to how the Base Class can tell what the type is.

But I am confused as to how it works.

You actually set _TypeRequired in each class and _ValidateType seems to
know what _TypeRequired is. In _ValidateType, at the line:

Type typeRequired = _TypeRequired;

Before it is actually executed - it seems to know what _TypeRequired is
!!! Yet I can't see where it is actually being set - just defined (either
as abstract or overridden).

It's a property, not a variable, so it is computed each time it is
referenced by calling the getter. The getter is simply "{ return
typeof(bool); }".
Right.

As Peter suggested, I was confused by the Debugger which apparently did the
get itself or just figured it out. But that it was this statement that
actually set the _TypeRequired variable - doing the get the very first
thing.

Thanks,

Tom
Nov 16 '07 #12

P: n/a
On 2007-11-15 17:33:44 -0800, "tshad" <tf*@dslextreme.comsaid:
So the _TypeRequired is really nothing until the "get" which would be during
the assignment here:

Type typeRequired = _TypeRequired;
Define "is" and "nothing". :)

_TypeRequired is a property; technically speaking, no property is
anything until you call the getter. On the other hand, you might
consider a property "something" if you know the value it will return.
With that point of view, _TypeRequired is different for each concrete
class, and is "something" the moment you instantiate the class.

But yes...you need to "get" a property before a property can really be
considered to have a value. The value it has is whatever the
property's getter returns at that moment, and more generally speaking,
you only know the value of the property at the instant it returns a
value.

Obviously for many classes and properties, the values are a bit more
resilient than that. But the only thing you can say is _generally_
true about a property is that it will return a value when you ask it to.
I assume that what happens when it gets to the this statement is that it
1) does the "get" on the _TypeRequired
2) Takes the returned value (system.boolean, system.string, system.integer
etc) and assignes it to typeRequired
That's correct. Note that this is exactly how any property works,
except that in this case the return value is hard-coded into the getter
rather than being computed or retrieved from some other variable as is
usually the case.
And then when you actually do the assignment of Data, it doesn't really
matter what the type is as the object pointer is now pointing at:

public object Data
{
get { return _objCurrent; }
set
{
if (value != null)
{
_ValidateType(value);
}
_objCurrent = value;
_fChanged = true;
}
}
I'm not really sure what you mean. An object reference (given the .NET
terminology, I prefer to use the word "reference" over "pointer" in
this situation) points (or rather, refers) to the data structure. It
wouldn't "point" to a specific property.
Since it would be something like:

bool temp;
BoolType boolTypeTemp = new BoolType();
boolTypeTemp.Data = true
temp = (bool)boolTypeTemp;

In the 3rd line, we are putting true into the object _objCurrent and
_objCurrent doesn't really care what it is.
If you're going to use this class or anything like it, you should
probably familiarize yourself with boxing, if you're not already. In
particular, it would be more precise to say that the value "true" is
boxed into an object instance, and the reference to _that_ instance is
what is stored in _objCurrent.
It is just an object. Of
course, before we actually assigned it we checked the type with
_ValidateType(value).

So now we have an object _objCurrent that is set to the value of true but
_objCurrent doesn't really know that it is a bool, just that it has a value
of true.
Well, all that _objCurrent "knows" is that it has a reference to
something that is an Object. It doesn't even know that the object has
a value type boxed inside it, never mind what the actual value of that
value type is.
Which, if I am not mistaken is just a place on the heap with a -1
one in it and _objCurrent is just a pointer to it. Correct?
To be honest, I have no idea. I'm used to a boolean type being stored
as 0 for false and 1 for true, but .NET could use -1 for all I know.

I try to avoid worrying about the internal representation as much as
possible, since the whole point of encapsulating data in higher-level
types is so that you don't care what the internal representation is.
And I haven't yet run into a need to know in .NET for bool, so I can't
actually answer that question. :)

Now, all that said...if one assumes that all that the BitConverter
class does is literally copy the bytes from the source type to a byte
array, and one further assumes that the sample code and output provided
with the GetBytes(bool) doc page is correct, then in .NET a bool is
stored as a 1, just as in other languages.

http://msdn2.microsoft.com/en-us/library/atf689tw.aspx
And when I return it, I need to cast it to bool since we are just passing
back an object which could be anything.
Yes. Thus the convenience property, TypedData, to do the casting for
you in an easier-to-read and easier-to-type way.
Also, I assume that a null would be a problem if I tried to pass it back a
null. If I did this, I would have a problem since bool can't be null.
Right?
Right. Though, you would have this in any context where you try to
copy a nullable version of a value type into a regular, non-nullable
version of a value type (for example, using .NET 2.0's Nullable<T>
generic type).

Basically, when you've stored a value type in a nullable
representation, since value types can't be null, you always have to
check for null before assigning them back. In your class here,
presumably you would use the IsNull property to do that, or of course
you could always just compare the Data property to null.

You wouldn't want to get the TypedData value before checking for null,
or else you'll get an exception casting the value back to bool.
(Though, in some designs it might be that's the behavior you want;
instead of checking for null, just let the exception happen and handle
it as appropriate).

See http://msdn2.microsoft.com/en-us/library/ms173224.aspx for one
technique for dealing with nullable-to-non-nullable assignments.
[...]
What I typically do is use camel case for my memory variables and Pascal
case for my objects, properties and functions.

Of course, this causes a problem in asp.net if I have a textbox named Name
and memory variable as name - now what do I do with my property. What I
typically do is at this point just change the textbox name to objName.

Not really very clean. I need to think it through better.
Well, for what it's worth, I recommend doing what works best for you.
Just because I use Hungarian and prefix non-public members with an
underscore, that doesn't mean it's a useful technique for everyone.

And note that I only use Hungarian for internal stuff. My public
properties follow the Microsoft recommendation for .NET naming, and
while I don't explicitly follow their recommendation for methods, the
Hungarian guidelines for naming methods is effectively a superset of
the .NET recommendations for the most part so there's not really any
difference.

That said, if you're running into naming conflicts with your current
style then, yes...you might want to think about it more. :)

Pete

Nov 16 '07 #13

P: n/a

"Peter Duniho" <Np*********@NnOwSlPiAnMk.comwrote in message
news:2007111519414875249-NpOeStPeAdM@NnOwSlPiAnMkcom...
On 2007-11-15 17:33:44 -0800, "tshad" <tf*@dslextreme.comsaid:
>So the _TypeRequired is really nothing until the "get" which would be
during
the assignment here:

Type typeRequired = _TypeRequired;

Define "is" and "nothing". :)

_TypeRequired is a property; technically speaking, no property is anything
until you call the getter. On the other hand, you might consider a
property "something" if you know the value it will return. With that
point of view, _TypeRequired is different for each concrete class, and is
"something" the moment you instantiate the class.

But yes...you need to "get" a property before a property can really be
considered to have a value. The value it has is whatever the property's
getter returns at that moment, and more generally speaking, you only know
the value of the property at the instant it returns a value.
I always looked at a property as a conduit to some value but that it didn't
do anything until you called it (get). So it was confusing that the value
seemed to be "something" before being called by the debugger. But in
actuality, I guess you could say the debugger was doing a "get" to get the
value.
Obviously for many classes and properties, the values are a bit more
resilient than that. But the only thing you can say is _generally_ true
about a property is that it will return a value when you ask it to.
>And then when you actually do the assignment of Data, it doesn't really
matter what the type is as the object pointer is now pointing at:

public object Data
{
get { return _objCurrent; }
set
{
if (value != null)
{
_ValidateType(value);
}
_objCurrent = value;
_fChanged = true;
}
}

I'm not really sure what you mean. An object reference (given the .NET
terminology, I prefer to use the word "reference" over "pointer" in this
situation) points (or rather, refers) to the data structure. It wouldn't
"point" to a specific property.
What I was saying was that when you do the line "_objCurrent = value;",
value can be anything (bool, int, string, etc). To the class it is just an
object (not a bool, int or string). The statement doesn't care, which is
why you need to do the ValidateType before. The value really gets put on
the heap and _objCurrent is just a pointer to that location. Right?
>
>Since it would be something like:

bool temp;
BoolType boolTypeTemp = new BoolType();
boolTypeTemp.Data = true
temp = (bool)boolTypeTemp;

In the 3rd line, we are putting true into the object _objCurrent and
_objCurrent doesn't really care what it is.

If you're going to use this class or anything like it, you should probably
familiarize yourself with boxing, if you're not already. In particular,
it would be more precise to say that the value "true" is boxed into an
object instance, and the reference to _that_ instance is what is stored in
_objCurrent.
I only sort of understand boxing.

If I understand it correctly, _objCurrent is just a pointer on the Stack
that points to something on the Heap.

When I assign true to an object, it does
1) a "memalloc" (from the C++ days) and grabs a portion of memory
2) puts the value (true in this case, "This is a test" in the case of a
string) there
3) then puts the pointer (reference) in _objCurrent.
>It is just an object. Of
course, before we actually assigned it we checked the type with
_ValidateType(value).

So now we have an object _objCurrent that is set to the value of true but
_objCurrent doesn't really know that it is a bool, just that it has a
value
of true.

Well, all that _objCurrent "knows" is that it has a reference to something
that is an Object. It doesn't even know that the object has a value type
boxed inside it, never mind what the actual value of that value type is.
What is confusing is that Data is type "object", as you said. How does it
know how much memory to allocate? I assume that the Property knows how much
data is being passed. Obviously, a string would/could take many bytes. We
do the _ValidateType to check the type, but then we just move the value
(which could be any type) to the heap.
>Which, if I am not mistaken is just a place on the heap with a -1
one in it and _objCurrent is just a pointer to it. Correct?

To be honest, I have no idea. I'm used to a boolean type being stored as
0 for false and 1 for true, but .NET could use -1 for all I know.
I agree. I am not sure what is put there either (I believe it is 0 for
false and -1 for true but it doesn't matter).
I try to avoid worrying about the internal representation as much as
possible, since the whole point of encapsulating data in higher-level
types is so that you don't care what the internal representation is. And
I haven't yet run into a need to know in .NET for bool, so I can't
actually answer that question. :)

Now, all that said...if one assumes that all that the BitConverter class
does is literally copy the bytes from the source type to a byte array, and
one further assumes that the sample code and output provided with the
GetBytes(bool) doc page is correct, then in .NET a bool is stored as a 1,
just as in other languages.

http://msdn2.microsoft.com/en-us/library/atf689tw.aspx
>And when I return it, I need to cast it to bool since we are just passing
back an object which could be anything.

Yes. Thus the convenience property, TypedData, to do the casting for you
in an easier-to-read and easier-to-type way.
>Also, I assume that a null would be a problem if I tried to pass it back
a
null. If I did this, I would have a problem since bool can't be null.
Right?

Right. Though, you would have this in any context where you try to copy a
nullable version of a value type into a regular, non-nullable version of a
value type (for example, using .NET 2.0's Nullable<Tgeneric type).

Basically, when you've stored a value type in a nullable representation,
since value types can't be null, you always have to check for null before
assigning them back. In your class here, presumably you would use the
IsNull property to do that, or of course you could always just compare the
Data property to null.

You wouldn't want to get the TypedData value before checking for null, or
else you'll get an exception casting the value back to bool. (Though, in
some designs it might be that's the behavior you want; instead of checking
for null, just let the exception happen and handle it as appropriate).

See http://msdn2.microsoft.com/en-us/library/ms173224.aspx for one
technique for dealing with nullable-to-non-nullable assignments.
Actually, I do have a Nullhandling class that does just like my last class
that we are working on and I plan on using the same techniques we did here
to make it work. I use it for moving data to and from my database records
and I use these classes to handle the nulls and track changes.

The call to move data from a database to my classes would be something like:

NullHandler.GetValueFromDbObject((object)user["UserID"],ref userID);

where userID is defined as:

private IntType userID = new IntType();

The code for the first part of my NullHandler is:
******************************************
using System;
using System.IO;
using FtsData;

namespace FtsData
{
[Serializable]
public sealed class NullHandler
{
private NullHandler()
{
}

public static void GetValueFromDbObject(object dbObjectValue, ref
StringType destination)
{
if (dbObjectValue == null || dbObjectValue == DBNull.Value)
{
// Set the Null flag
destination.SetNull();
return;
}
destination.Data = Convert.ToString(dbObjectValue);
}

public static void GetValueFromDbObject(object dbObjectValue, ref CharType
destination)
{
if (dbObjectValue == null || dbObjectValue == DBNull.Value)
{
// Set the Null flag
destination.SetNull();
return;
}
destination.Data = Convert.ToChar(dbObjectValue);
}

public static void GetValueFromDbObject(object dbObjectValue, ref BoolType
destination)
{
if (dbObjectValue == null || dbObjectValue == DBNull.Value)
{
// Return the max value.
destination.SetNull();
return;
}

// Check for a string.
string str = dbObjectValue as string;

// If the string is not null, check for empty.
if (str != null)
{
// If the string is empty, return the max value.
if (str == string.Empty)
{
// Set the Null flag
destination.SetNull();
return;
}
}
// Return the object, converted to a decimal.
destination.Data = Convert.ToBoolean(dbObjectValue);
}

******************************************

Since a lot of the data is the same I was looking at whether to do the same
type of thing. I'm not sure if it is worth it or not as it does work as it
is but I may do it just for the practice.
>
>[...]
What I typically do is use camel case for my memory variables and Pascal
case for my objects, properties and functions.

Of course, this causes a problem in asp.net if I have a textbox named
Name
and memory variable as name - now what do I do with my property. What I
typically do is at this point just change the textbox name to objName.

Not really very clean. I need to think it through better.

Well, for what it's worth, I recommend doing what works best for you.
Just because I use Hungarian and prefix non-public members with an
underscore, that doesn't mean it's a useful technique for everyone.

And note that I only use Hungarian for internal stuff. My public
properties follow the Microsoft recommendation for .NET naming, and while
I don't explicitly follow their recommendation for methods, the Hungarian
guidelines for naming methods is effectively a superset of the .NET
recommendations for the most part so there's not really any difference.

That said, if you're running into naming conflicts with your current style
then, yes...you might want to think about it more. :)
True.

Thanks,

Tom
>

Nov 16 '07 #14

P: n/a
On 2007-11-15 21:46:48 -0800, "tshad" <tf*@dslextreme.comsaid:
I always looked at a property as a conduit to some value but that it didn't
do anything until you called it (get). So it was confusing that the value
seemed to be "something" before being called by the debugger. But in
actuality, I guess you could say the debugger was doing a "get" to get the
value.
Not only could I say that, I would. :)

That's how properties work. You have to call the getter method to get
the value. Since calling a getter is an instaneous event, rather than
something that's stored somewhere, a property's value is only known at
the time you call the getter.

Some properties never change in value, such as the one we're talking
about here. Others are more conventional, and change in value only
when you call the setter. And still others are changing in value all
the time (at this extreme, see for example DateTime.Now).

The one thing that all properties have in common is that whatever one
might consider the "value" of a property, the only way to know for sure
what the value is at any given moment is to call the getter for the
property. And the instance you call that getter, there are no
fundamental guarantees about what might be returned the next time you
call the getter (though many classes of course provide a guarantee
above and beyond what the language offers).

To me, it's sort of like a little Heisenberg thing going on. You have
to measure the state of the property to know its value. Granted, for
most properties measuring the state doesn't itself necessarily change
the state, but it could and more importantly you still can't say
anything about the future state of the property even having obtained
the state at some instantaneous point in time. :)

>I'm not really sure what you mean. An object reference (given the .NET
terminology, I prefer to use the word "reference" over "pointer" in this
situation) points (or rather, refers) to the data structure. It wouldn't
"point" to a specific property.

What I was saying was that when you do the line "_objCurrent = value;",
value can be anything (bool, int, string, etc). To the class it is just an
object (not a bool, int or string). The statement doesn't care, which is
why you need to do the ValidateType before. The value really gets put on
the heap and _objCurrent is just a pointer to that location. Right?
Basically, yes.
I only sort of understand boxing.

If I understand it correctly, _objCurrent is just a pointer on the Stack
that points to something on the Heap.
Not really. _objCurrent is a field inside a class. All classes are
reference types, which means that all classes are allocated from the
heap. So _objCurrent is a memory location in the heap, that references
something else that's stored in the heap.
When I assign true to an object, it does
1) a "memalloc" (from the C++ days) and grabs a portion of memory
2) puts the value (true in this case, "This is a test" in the case of a
string) there
3) then puts the pointer (reference) in _objCurrent.
That much is basically correct, not counting the hand-waving. :)
There is more to boxing though than just allocating a large enough area
to hold the value itself. It's oversimplifying things to say that just
the value is stored (that is, a boxed int for example is going to take
more space than just the 32 bits for the int).
>Well, all that _objCurrent "knows" is that it has a reference to something
that is an Object. It doesn't even know that the object has a value type
boxed inside it, never mind what the actual value of that value type is.

What is confusing is that Data is type "object", as you said. How does it
know how much memory to allocate?
Because a reference is always just 32 bits. The act of boxing a value
type needs to know how much space to allocate, to contain the value
type along with the class that's containing it. But once the value
type has been boxed (and this occurs _before_ the assignment to the
Data property), it's just a regular reference and always only takes as
much space to store as any reference: 32 bits.

(Ignoring the possibility of a 64-bit .NET for the moment :) )
I assume that the Property knows how much
data is being passed. Obviously, a string would/could take many bytes. We
do the _ValidateType to check the type, but then we just move the value
(which could be any type) to the heap.
Well, a string is even easier, since the String class is already a
reference type. No boxing has to happen; the reference that is already
a reference to the string instance is simply copied to the _objCurrent
field that is the backing store for the Data property.

But again, the property does know how much data is being passed,
because that data is always 32 bits.
[...]
Actually, I do have a Nullhandling class that does just like my last class
that we are working on and I plan on using the same techniques we did here
to make it work. I use it for moving data to and from my database records
and I use these classes to handle the nulls and track changes.

The call to move data from a database to my classes would be something like:

NullHandler.GetValueFromDbObject((object)user["UserID"],ref userID);

where userID is defined as:

private IntType userID = new IntType();
Well, the first thing I notice is that you're using the "ref" keyword
inappropriately. The "userID" variable is already a reference type.
So the parameter is passing a reference. The reference is passed by
value, but it's still a reference and so even without the "ref" any
changes you make to the object in the called method will be reflected
when accessing the instance through "userID".

See Jon Skeet's most excellent article on the topic:
http://www.yoda.arachsys.com/csharp/parameters.html
Since a lot of the data is the same I was looking at whether to do the same
type of thing. I'm not sure if it is worth it or not as it does work as it
is but I may do it just for the practice.
Well, at the very least it does seem like you could consolidate all of
the "check for null, convert to type" code somehow. It sure seems like
all of those GetValueFromDbObject() overloads could be coalesced into a
single method that handles the checking for null.

The way you've written that code, it appears that the caller makes the
determination of type before making the call. So one approach would be
to add a conversion method into your type classes (similar to the
_TypeRequired property, it would be abstract and then implemented by
each concrete type), instantiate the necessary class before calling
GetValueFromDbObject(), and then in that method call the conversion
method to convert from the database object to the necessary C# type for
storage.

I don't know enough about the overall design to know that's the best
way to handle it, but given the code you've posted so far, it's
certainly one way and would at least be better than having all those
overloads. :)

Pete

Nov 16 '07 #15

P: n/a
"Peter Duniho" <Np*********@NnOwSlPiAnMk.comwrote in message
news:2007111600330350073-NpOeStPeAdM@NnOwSlPiAnMkcom...
On 2007-11-15 21:46:48 -0800, "tshad" <tf*@dslextreme.comsaid:
>I always looked at a property as a conduit to some value but that it
didn't
do anything until you called it (get). So it was confusing that the
value
seemed to be "something" before being called by the debugger. But in
actuality, I guess you could say the debugger was doing a "get" to get
the
value.

Not only could I say that, I would. :)

That's how properties work. You have to call the getter method to get the
value. Since calling a getter is an instaneous event, rather than
something that's stored somewhere, a property's value is only known at the
time you call the getter.

Some properties never change in value, such as the one we're talking about
here. Others are more conventional, and change in value only when you
call the setter. And still others are changing in value all the time (at
this extreme, see for example DateTime.Now).

The one thing that all properties have in common is that whatever one
might consider the "value" of a property, the only way to know for sure
what the value is at any given moment is to call the getter for the
property. And the instance you call that getter, there are no fundamental
guarantees about what might be returned the next time you call the getter
(though many classes of course provide a guarantee above and beyond what
the language offers).

To me, it's sort of like a little Heisenberg thing going on. You have to
measure the state of the property to know its value. Granted, for most
properties measuring the state doesn't itself necessarily change the
state, but it could and more importantly you still can't say anything
about the future state of the property even having obtained the state at
some instantaneous point in time. :)

>>I'm not really sure what you mean. An object reference (given the .NET
terminology, I prefer to use the word "reference" over "pointer" in this
situation) points (or rather, refers) to the data structure. It
wouldn't
"point" to a specific property.

What I was saying was that when you do the line "_objCurrent = value;",
value can be anything (bool, int, string, etc). To the class it is just
an
object (not a bool, int or string). The statement doesn't care, which is
why you need to do the ValidateType before. The value really gets put on
the heap and _objCurrent is just a pointer to that location. Right?

Basically, yes.
>I only sort of understand boxing.

If I understand it correctly, _objCurrent is just a pointer on the Stack
that points to something on the Heap.

Not really. _objCurrent is a field inside a class. All classes are
reference types, which means that all classes are allocated from the heap.
So _objCurrent is a memory location in the heap, that references something
else that's stored in the heap.
I understand that it is a field. But I thought that since the _objCurrent
is an object type that it is just a pointer but not actually an object until
it is assigned to something so it is null.

As far as boxing and the heap go, I assumed it was a pointer to the heap
from articles such as this:

http://www.c-sharpcorner.com/UploadF...e-0f4cc23f8e6c

I may not have understood it completely.
>When I assign true to an object, it does
1) a "memalloc" (from the C++ days) and grabs a portion of memory
2) puts the value (true in this case, "This is a test" in the case of a
string) there
3) then puts the pointer (reference) in _objCurrent.

That much is basically correct, not counting the hand-waving. :) There
is more to boxing though than just allocating a large enough area to hold
the value itself. It's oversimplifying things to say that just the value
is stored (that is, a boxed int for example is going to take more space
than just the 32 bits for the int).
Really?

Does it have more information about the actual object, such as what type of
object it is?
>
>>Well, all that _objCurrent "knows" is that it has a reference to
something
that is an Object. It doesn't even know that the object has a value
type
boxed inside it, never mind what the actual value of that value type is.

What is confusing is that Data is type "object", as you said. How does
it
know how much memory to allocate?

Because a reference is always just 32 bits. The act of boxing a value
type needs to know how much space to allocate, to contain the value type
along with the class that's containing it. But once the value type has
been boxed (and this occurs _before_ the assignment to the Data property),
it's just a regular reference and always only takes as much space to store
as any reference: 32 bits.
That is what is confusing about boxing.

According to the article above, unless I missed something, boxing actually
moves the data and you are looking at a different piece of data.

For example:

string A = "something"
string B;
B = A

Both A and B are referencing the same location. Such that if I say 'A =
"Something else";', A and B will both be equal to "Something Else".

But if you do
string A = "something";
object B;
B = A;
A = "Something Else"

A and B point to different locations whereas A will be "Something Else" and
B will be "something". Both A and B are pointers in both examples.

Maybe it is different with ints and strings.
(Ignoring the possibility of a 64-bit .NET for the moment :) )
>I assume that the Property knows how much
data is being passed. Obviously, a string would/could take many bytes.
We
do the _ValidateType to check the type, but then we just move the value
(which could be any type) to the heap.

Well, a string is even easier, since the String class is already a
reference type. No boxing has to happen; the reference that is already a
reference to the string instance is simply copied to the _objCurrent field
that is the backing store for the Data property.

But again, the property does know how much data is being passed, because
that data is always 32 bits.
>[...]
Actually, I do have a Nullhandling class that does just like my last
class
that we are working on and I plan on using the same techniques we did
here
to make it work. I use it for moving data to and from my database
records
and I use these classes to handle the nulls and track changes.

The call to move data from a database to my classes would be something
like:

NullHandler.GetValueFromDbObject((object)user["UserID"],ref userID);

where userID is defined as:

private IntType userID = new IntType();

Well, the first thing I notice is that you're using the "ref" keyword
inappropriately. The "userID" variable is already a reference type. So
the parameter is passing a reference. The reference is passed by value,
but it's still a reference and so even without the "ref" any changes you
make to the object in the called method will be reflected when accessing
the instance through "userID".
That may be the case.

I wrote this a few years ago and it does work. It seems that it didn't work
without the ref keyword. But they have been that I started building this
with a scalar that was not a reference type and I just kept the code the
same.
>
See Jon Skeet's most excellent article on the topic:
http://www.yoda.arachsys.com/csharp/parameters.html
>Since a lot of the data is the same I was looking at whether to do the
same
type of thing. I'm not sure if it is worth it or not as it does work as
it
is but I may do it just for the practice.

Well, at the very least it does seem like you could consolidate all of the
"check for null, convert to type" code somehow. It sure seems like all of
those GetValueFromDbObject() overloads could be coalesced into a single
method that handles the checking for null.
That was what I was thinking about doing.
>
The way you've written that code, it appears that the caller makes the
determination of type before making the call. So one approach would be to
add a conversion method into your type classes (similar to the
_TypeRequired property, it would be abstract and then implemented by each
concrete type), instantiate the necessary class before calling
GetValueFromDbObject(), and then in that method call the conversion method
to convert from the database object to the necessary C# type for storage.
Before I was thinking about rewritting the NullHandler up until last night.
And it was more necessary since, if you remember, the old DataType Classes
had variables that were the type of the class (BoolType class had First as a
boolean, IntType class had First as an int). Now the variables in the class
are objects. So maybe I can now consolidate them into the DataType class.

The whole point of the NullHandler class is to handle data going to and from
a database where the values can be null in the database and not in my c#
code.

When calling to 2 types of calls in my NullHandler:

NullHandler.GetValueFromDbObject((object)user["UserID"],ref userID);

and in my Property where I use both get the data from the DB and Set the
Data to back to the DB

public object DivisionID
{
get
{
object value = null;
return NullHandler.SetDbObjectValueFromValue(divisionID,r ef value);
}
set
{
NullHandler.GetValueFromDbObject(value,ref divisionID);
}
}

The code in the NullHandler for my SetDBObjectValueFromValue would look
something like:

public static object SetDbObjectValueFromValue(LongType sourceValue, ref
object dbObjectValue)
{
if(sourceValue.IsNull())
dbObjectValue = DBNull.Value;
else
dbObjectValue = sourceValue.Data;
return dbObjectValue;
}

Most of this was based on the objects fields being of a specific type and in
the new style they are all objects.
I don't know enough about the overall design to know that's the best way
to handle it, but given the code you've posted so far, it's certainly one
way and would at least be better than having all those overloads. :)
Sounds good to me.

Thanks,

Tom
Nov 16 '07 #16

P: n/a
On 2007-11-18 12:55:03 -0800, "tshad" <tf*@dslextreme.comsaid:
I think I understand boxing a little better now.

After reading your information and a couple of other articles - I think I
have a better idea what it is and why it is used. The problem was the WHY.
I had seen other articles on the HOW but not much on the why:

int i,j;
object o = i; // Boxed
j = (object) o/ // unboxed.

This shows how it is done but not why you would use it.
Has the "why" been adequately explained yet? Or would you like
elaboration on that?
You're right in that I didn't understand the string type not being boxed and
the values being boxed and why they were different. But now if I understand
it correctly:

1) value types are stored on the stack (faster)
Value types are stored on the stack when they are local variables. But
as I think you've seen elsewhere in this thread, a value type can exist
inside a class and in that case the value type is stored in the heap
with the rest of the class instance.

But as far as the "faster" goes, yes...to some extent value types have
less overhead than reference types, and so can perform better in
certain cases.
2) reference types are stored on the heap and have a reference/pointer to
the object that is on the heap.
Right. That is, a reference type variable itself would still be stored
on the stack if it's a local variable, but only the reference is stored
on the stack. The instance itself is stored in the heap.
3) value types are copied to the heap and made into an object and reference
type (in essence) that now has a reference/pointer pointing to the new
object.
Right, that's boxing.
4) String types are already reference types and all we are doing when we do
"object o = str" is create a new reference/pointer that points to the object
on the heap.
Depends on your definition of "create". My view is that the assignment
doesn't create anything. The source and destination already exist, and
the reference is copied from one to the other.

But yes, in another sense a new copy of the reference is "created",
replacing whatever was in the variable before (and in that sense, if
the reference is "created", the previous value of the variable is
"destroyed").
In the case of a non-string object, the object is the same but we have 2
pointers to that same object. If the object changes value and both
references point to the same object, they will be the same.
Well, that would be true for a string object too, if there was any way
to actually change a string.

Likewise, if you assign a new reference to a reference type variable,
that doesn't affect other variables that might have referenced the same
object that variable previously referenced. For example:

object A = new object();
object B = A;

A = new object();

That's just like the string case. Assigning a new reference to A
doesn't change what B references. This works for _any_ reference type
variable.

The thing about the string class is that assigning a new string
instance to a string type variable is the _only_ way to change the
string value of that variable. Mutable classes, you can call some
method or set a property or something like that, and that will change
the instance itself, without requiring you to assign a new instance of
the class to a variable.

I realize that the distinction might seem subtle, or even pedantic.
But I think it's a very important distinction. In particular, it's
very important to understand that with respect to the code we've seen
in this thread, the string class isn't really so different from other
classes. Because it's immutable, you _have_ to write code like we've
seen here, while other classes might provide other options. But even
with a mutable class, if you write code like we've written here, it'll
behave just like the string class (except of course for the one example
I showed specifically designed to change a class instance without
reassiging the variable).
But in the case of a string, which is immutable, the 1st reference would
point to the first string and the 2nd reference (after the string is
changed) will point to the new string. And that would be the case, even if
we didn't move it to a new object.
Even if we didn't move what to a new object?

As far as "the string is changed", I think it's important to
understand, the original string isn't changed. You create a whole new
string instance, and the string type variable itself is changed to
reference the new string instance.

Again, maybe it seems pedantic, but I think it's important to
understand the difference between the variable referencing some data
and the data itself, and along with that to make sure the language one
is using is clear about that difference.
string A = "something";
string B;
B = A;
A += " Else";

gives me the same result as:

string s1 = "something";
object o1 = s1;
s1 += " Else";

Where A <B and o1 <s1 because in both cases a new string is created even
though we think we are changing the strings.
Well, you might think you are changing the strings. :)

Seriously though, it is practically always the case that when you are
writing an assignment to a reference, you're replacing the reference
held by the variable. The obvious exception is of course where for
whatever reason your code sometimes assigns a reference to a variable
when it already holds that reference. Another example, one that I hope
is _extremely_ uncommon, would be in the case of an operator that's
overloaded to return the original instance reference for one of the
operands.

But as a general rule of thumb, changing an instance will go through
some member of the instance, while changing a reference value will
involve the assignment operator. The string class has no member of the
class that allows the instance to be changed, which is what makes it
immutable. But the "changing a reference value" is the same for the
string class as it is for any other class, immutable or not.
I also found a better article/tutorial which I think was trying to say the
same thing as the first one but this one does it better. He isn't
addressing the string reference type but address reference types in general.
http://www.jaggersoft.com/csharp_cou...iles/frame.htm

I think he is saying the same thing you are saying (but he also doesn't go
into the string reference type).
Yes. I didn't care for the web design very much :), but it seems like
a better discussion of the concept.
[...]
>_objCurrent isn't on the stack, which is all I was pointing out.

I assume that _objCurrent isn't on the stack because the object is not on
the stack and all reference types are stored on the heap. But is
_objCurrent just a pointer (reference) to the actual object (on the heap).
Your assumption is correct. And yes, _objCurrent is a variable that
contains a reference to the actual object on the heap.
[...]
The boxing of the variable "i" does not in any way relate the variable "i"
>to something on the heap. It _copies_ the value from the variable "i"
into a completely new data structure. Once this is done, "i" is
completely irrelevant to the reference instance. It's very misleading to
refer to that instance as being "i on the heap".

It may be misleading but I think the value that gets copied does get copied
to the heap. But in the case of an Class Object that is already on the
heap, you are copying the value from a heap location to a heap location.
I think you lost me. I'm not sure what "Class Object" refers to (maybe
something in the previously referenced web page?), but assuming it's a
class, it's a reference type and assigning the reference to the
instance to any variable just copies the reference, not the class
instance itself.

If that's what you meant, then I'll agree with that. :)
>[...]
The current value of "i" is passed into the constructor, where it's copied
to the private field "_value". You can read it back out, which then
copies the value from the private field to wherever you assign it. But "i"
is only relevant when the instance is first constructed, and there only as
it's passed by value to the constructor.

So in this case I have "i" which is a value Type and boxed.i (if i were
public) which are completely different even if they have the same value at
the start. If I then change "i" to 30, boxed.i will still = 5.
Exactly.
[...]
>In that case, your statement that "B will be 'something'" is not true. B
continues to reference the same instance as A, and having changed that
instance so that it contains "something else" instead, the instance of
Mutable that B refers to will contain "something else" (because it's the
same instance).
I got it.

If the string is inside the object and A and B both pointed at the object
even if the string changed INSIDE the object, since A and B are both
pointing at the same object with the string changed and therefore A.String
and B.String would be the same.
Right.
But in the above case:

string A = "something";
object B;
B = A;
A = "Something Else"

You really do have 2 references to 2 different objects (a string and and an
object) and NOT 2 references to the same object.
Well, the _variable_ type is object for the second reference, but after
the third line ("B = A") you still only have one object: the original
string ("something").

Using the variable B you could only do things with the instance that
are defined in the class Object. But the instance is still a string.

After the fourth line, you now have two objects, both of them strings.
The original string is now only accessible via a variable typed as
Object, so you can only use the things defined in the Object type. But
you could cast the reference held in B back to a string, and you'd then
be able to do all the things the class String defines with the instance.
And because of the way a
string works when you change A you actually get a 3rd object
No, only a second object. See above.
and the
original object is dereferenced by 1 and if nothing else is referencing it,
the GC will get rid of it.
For what it's worth: there's no ref-counting in the GC. The garbage
collector just scans the variables referencing data, and for any object
for which it doesn't find something referencing it, it collects that
object (to oversimplify the mechanism a bit :) ).

I'm not sure what you mean by "nothing else". To me, that means
"nothing other than B", and if so the statement's not correct. B
referencing the instance is sufficient to prevent it from being
collected. If B is the only variable referencing the instance however,
then once B is assigned something else, or simply goes out of scope,
then yes...the original instance can be collected.
[...]
>Mutable A, C;
object B;

A = new Mutable("something");
B = A;
A.String = "something else";
C = (Mutable)B;
Console.WriteLine(C.String);

[...]
I think I have it. In the above example, I think A = B = C, since all 3 are
reference types and point to the same object (and none are strings).
That's right.
>[...]
Maybe it is different with ints and strings.

The int type and string type are _definitely_ handled differently. An int
is a value type, and so to assign an int instance to an object variable,
it has to be boxed. But a string is a reference type, and assigning a
string instance to an object variable requires no such work.

But the string is a special type of reference type (immutable) in that you
can't just assign the reference to another string and assume they will stay
the same, since any change to the string will now change the object the
reference is pointing to. Correct?
Sort of. I think I explained this above, but just to reiterate:

Knowing that the String class is immutable, you know that if two or
more variables do reference the same instance, that that instance will
never change.

In that respect it's not correct to write "any change to the string",
since there's no such thing. A string is immutable; there can be no
change to the string.

As far as an assignemnt goes, if you assign a new instance to one of
the variables, none of the other variables will be affected by the
assignment. But that is true for any class, whether mutable or
immutable.

Having a class that's immutable gives you a certain guarantee for a
given instance, and thus for multiple variables all referencing that
instance. And it also places a specific requirement on how you can
change the data a particular variable describes: you can only replace
the reference with a new reference to a different instance, rather than
modifying the instance itself.

Basically: immutable places a requirement that an assignment be used
for specific kinds of behavior, but it doesn't actually affect what
happens during an assignment. Assignments have the same effect for
mutable classes as they do for immutable classes.

Pete

Nov 19 '07 #17

P: n/a
"Peter Duniho" <Np*********@NnOwSlPiAnMk.comwrote in message
news:2007111819511975249-NpOeStPeAdM@NnOwSlPiAnMkcom...
On 2007-11-18 12:55:03 -0800, "tshad" <tf*@dslextreme.comsaid:
>I think I understand boxing a little better now.

After reading your information and a couple of other articles - I think I
have a better idea what it is and why it is used. The problem was the
WHY.
I had seen other articles on the HOW but not much on the why:

int i,j;
object o = i; // Boxed
j = (object) o/ // unboxed.

This shows how it is done but not why you would use it.

Has the "why" been adequately explained yet? Or would you like
elaboration on that?
I am always looking for different views on the issue as each one helps a
little more, as in this case. This excercise and various articles have
helped me to understand it.

I guess the question is not only WHY but WHEN. Obviously, it is the case
here.

I did try this class with my data in place of my old NullHandler and I think
this class is going to do what I need.

Here was what I found:

Instead of:

NullHandler.GetValueFromDbObject((object)user["UserID"],ref userID);

I found I can do:

StringType lastName = new StringType();
StringType email2 = new StringType();
lastName.Data = (object)dbReader["FirstName"];
email2.Data = (object)dbReader["Email2"];

At first I tried to cast them as string:
lastName.Data = (string)dbReader["FirstName"];
email2.Data = (string)dbReader["Email2"];

And that works fine, unless the value is null. In that case I get an error:

"Specified cast is not valid".

Not sure why that is since a string can be null.

string stemp;
stemp = null;

Works fine. So why would (string)dbReader["Email2"] not work?

Casting it as (object) works whether it is a null or not. But when it was
cast as an object I did get an error at the ValidateType function at the
line:

if (!typeRequired.IsInstanceOfType(obj))
{
throw new ArgumentException("assigned value type of " +
obj.GetType().Name + " is incompatible with required type of " +
typeRequired.Name);
}

The error is:

"assigned value type of DBNull is incompatible with required type of
String"

Once I saw that I realized I would need to change the line before call to
the ValidateType function to:

if ((value != null) && (value != DBNull.Value))
{
_ValidateType(value);
}
and that fixes that.

I also have to look at the TypedData properties also as they also give me
the Invalid Cast for it also - which if you remember is:

get { return (string)Data; }
>
>4) String types are already reference types and all we are doing when we
do
"object o = str" is create a new reference/pointer that points to the
object
on the heap.

Depends on your definition of "create". My view is that the assignment
doesn't create anything. The source and destination already exist, and
the reference is copied from one to the other.

But yes, in another sense a new copy of the reference is "created",
replacing whatever was in the variable before (and in that sense, if the
reference is "created", the previous value of the variable is
"destroyed").
What I meant was that the statement creates a new reference "o" that will
point to the same location as "str" which is where the string actually is.
>In the case of a non-string object, the object is the same but we have 2
pointers to that same object. If the object changes value and both
references point to the same object, they will be the same.

Well, that would be true for a string object too, if there was any way to
actually change a string.
Right.

But what I was saying that it isn't the same as the string since if you
change the string in any way "another" object is created and then one of the
references would be pointing at the original string and the other reference
would be pointing at the new string.
Likewise, if you assign a new reference to a reference type variable, that
doesn't affect other variables that might have referenced the same object
that variable previously referenced. For example:

object A = new object();
object B = A;

A = new object();
Right, but that is because YOU are creating a new object. In the string
case, the new object is being created because you changed the string. In a
non-string object, this would not be the case. If you said B.something =
15, both A and B would still point to the same object.
>
That's just like the string case. Assigning a new reference to A doesn't
change what B references. This works for _any_ reference type variable.

The thing about the string class is that assigning a new string instance
to a string type variable is the _only_ way to change the string value of
that variable. Mutable classes, you can call some method or set a
property or something like that, and that will change the instance itself,
without requiring you to assign a new instance of the class to a variable.

I realize that the distinction might seem subtle, or even pedantic. But I
think it's a very important distinction. In particular, it's very
important to understand that with respect to the code we've seen in this
thread, the string class isn't really so different from other classes.
Because it's immutable, you _have_ to write code like we've seen here,
while other classes might provide other options. But even with a mutable
class, if you write code like we've written here, it'll behave just like
the string class (except of course for the one example I showed
specifically designed to change a class instance without reassiging the
variable).
Right.

You are talking about a value type, I assume. Since you will have a value
type variable and a reference type variable.
>But in the case of a string, which is immutable, the 1st reference would
point to the first string and the 2nd reference (after the string is
changed) will point to the new string. And that would be the case, even
if
we didn't move it to a new object.

Even if we didn't move what to a new object?
Not sure what I meant there either :(
>
As far as "the string is changed", I think it's important to understand,
the original string isn't changed. You create a whole new string
instance, and the string type variable itself is changed to reference the
new string instance.

Again, maybe it seems pedantic, but I think it's important to understand
the difference between the variable referencing some data and the data
itself, and along with that to make sure the language one is using is
clear about that difference.
I agree.
>
>string A = "something";
string B;
B = A;
A += " Else";

gives me the same result as:

string s1 = "something";
object o1 = s1;
s1 += " Else";

Where A <B and o1 <s1 because in both cases a new string is created
even
though we think we are changing the strings.

Well, you might think you are changing the strings. :)

Seriously though, it is practically always the case that when you are
writing an assignment to a reference, you're replacing the reference held
by the variable. The obvious exception is of course where for whatever
reason your code sometimes assigns a reference to a variable when it
already holds that reference. Another example, one that I hope is
_extremely_ uncommon, would be in the case of an operator that's
overloaded to return the original instance reference for one of the
operands.

But as a general rule of thumb, changing an instance will go through some
member of the instance, while changing a reference value will involve the
assignment operator. The string class has no member of the class that
allows the instance to be changed, which is what makes it immutable. But
the "changing a reference value" is the same for the string class as it is
for any other class, immutable or not.
I agree. A reference is a reference.

[...]
>The boxing of the variable "i" does not in any way relate the variable
"i"
>>to something on the heap. It _copies_ the value from the variable "i"
into a completely new data structure. Once this is done, "i" is
completely irrelevant to the reference instance. It's very misleading
to
refer to that instance as being "i on the heap".

It may be misleading but I think the value that gets copied does get
copied
to the heap. But in the case of an Class Object that is already on the
heap, you are copying the value from a heap location to a heap location.

I think you lost me. I'm not sure what "Class Object" refers to (maybe
something in the previously referenced web page?), but assuming it's a
class, it's a reference type and assigning the reference to the instance
to any variable just copies the reference, not the class instance itself.
I was just making the point that a value type gets copied from the stack to
the heap. But if the value type is in an object and gets boxed there, it is
already on the heap (since it is part of the object) and it is actually
getting copied from the heap to another location on the heap. Not really
important just that fact that a value type is not always on the stack (if it
is part of an object). That wasn't made clear in either of the articles.
>
If that's what you meant, then I'll agree with that. :)
>>[...]
The current value of "i" is passed into the constructor, where it's
copied
to the private field "_value". You can read it back out, which then
copies the value from the private field to wherever you assign it. But
"i"
is only relevant when the instance is first constructed, and there only
as
it's passed by value to the constructor.

So in this case I have "i" which is a value Type and boxed.i (if i were
public) which are completely different even if they have the same value
at
the start. If I then change "i" to 30, boxed.i will still = 5.

Exactly.
>[...]
>>In that case, your statement that "B will be 'something'" is not true.
B
continues to reference the same instance as A, and having changed that
instance so that it contains "something else" instead, the instance of
Mutable that B refers to will contain "something else" (because it's the
same instance).
I got it.

If the string is inside the object and A and B both pointed at the
object
even if the string changed INSIDE the object, since A and B are both
pointing at the same object with the string changed and therefore
A.String
and B.String would be the same.

Right.
>But in the above case:

string A = "something";
object B;
B = A;
A = "Something Else"

You really do have 2 references to 2 different objects (a string and and
an
object) and NOT 2 references to the same object.

Well, the _variable_ type is object for the second reference, but after
the third line ("B = A") you still only have one object: the original
string ("something").

Using the variable B you could only do things with the instance that are
defined in the class Object. But the instance is still a string.

After the fourth line, you now have two objects, both of them strings.
The original string is now only accessible via a variable typed as Object,
so you can only use the things defined in the Object type. But you could
cast the reference held in B back to a string, and you'd then be able to
do all the things the class String defines with the instance.
>And because of the way a
string works when you change A you actually get a 3rd object

No, only a second object. See above.
You're right.

The first string won't go away because B is pointing at it, so we only have
2 objects.
[...]
>>The int type and string type are _definitely_ handled differently. An
int
is a value type, and so to assign an int instance to an object variable,
it has to be boxed. But a string is a reference type, and assigning a
string instance to an object variable requires no such work.

But the string is a special type of reference type (immutable) in that
you
can't just assign the reference to another string and assume they will
stay
the same, since any change to the string will now change the object the
reference is pointing to. Correct?

Sort of. I think I explained this above, but just to reiterate:

Knowing that the String class is immutable, you know that if two or more
variables do reference the same instance, that that instance will never
change.

In that respect it's not correct to write "any change to the string",
since there's no such thing. A string is immutable; there can be no
change to the string.
I think it is just the language here. I agree that you can't change the
string. I was just saying that if you were trying to make a change to the
string (any change) would just create another string/object with the result.
Even though it looks like the string changed - it actually didn't you are
now pointing at a new location with the changed string.

Tom
Nov 19 '07 #18

P: n/a
On 2007-11-19 00:49:48 -0800, "tshad" <tf*@dslextreme.comsaid:
[...]
StringType lastName = new StringType();
StringType email2 = new StringType();
lastName.Data = (object)dbReader["FirstName"];
email2.Data = (object)dbReader["Email2"];

At first I tried to cast them as string:
lastName.Data = (string)dbReader["FirstName"];
email2.Data = (string)dbReader["Email2"];

And that works fine, unless the value is null. In that case I get an error:

"Specified cast is not valid".

Not sure why that is since a string can be null.
Based on your later discussion of this issue, it appears to me that
when you write "the value is null", it's not really null.

In spite of its name, an instance of the DBNull type is not actually a
null as far as C# is concerned. It's an actual instance of an object,
and in this case one that's incompatible with the String type. You can
cast it to Object, because you can cast anything to Object. In fact,
in the code you wrote above you don't even need the cast. You can
assign anything to Object without casting.

The other thing you should be careful about is the type returned by
"dbReader[]" more generally. I don't know what type that is (I do very
little database work, so forgive me if it's something obvious :) ), but
presumably it's always returning a specific type, and probably that
type is Object. This means that when value types are returned, they
are already boxed.

This doesn't really affect how you'd use it -- even if you assigned an
unboxed value type to the Data property, it will be boxed for you in
the conversion to Object. But I think it's a good thing to be aware of
what's exactly going on.
string stemp;
stemp = null;

Works fine. So why would (string)dbReader["Email2"] not work?
Because the value being cast isn't "null", it's a reference to an
instance of "DBNull".
Casting it as (object) works whether it is a null or not.
That's because "DBNull" is an instance of type Object, but it's not an
instance of type String.
[...]
Once I saw that I realized I would need to change the line before call to
the ValidateType function to:

if ((value != null) && (value != DBNull.Value))
{
_ValidateType(value);
}
and that fixes that.
Well, it fixes the validation error. Whether it's really what you want
to do, I'm not sure. For one, unless you change the IsNull property,
you're not going to deal with value types correctly. Presumably, you'd
be checking IsNull before assigning an instance of DataType, but in
this case the data will be non-null (even if it's an instance of
DBNull). But casting DBNull in the case of a value type will throw an
exception, just like as if you'd tried to cast an actual null reference
to a value type.

Personally, I would fix it by converting DBNull's to actual nulls:

if (value is DBNull)
{
value = null;
}
if (value != null)
...

(Note: I can't recall off the top of my head whether you can actually
assign to the implicit "value" parameter; seems like you should be able
to but if not, you can just copy it to a local variable in the setter
and use that local variable instead of "value")
I also have to look at the TypedData properties also as they also give me
the Invalid Cast for it also - which if you remember is:

get { return (string)Data; }
Right. Same problem...you don't actually have a null value, you've got
a reference to a DBNull instance.
>>4) String types are already reference types and all we are doing when we
do
"object o = str" is create a new reference/pointer that points to the
object
on the heap.

Depends on your definition of "create". My view is that the assignment
doesn't create anything. The source and destination already exist, and
the reference is copied from one to the other.

But yes, in another sense a new copy of the reference is "created",
replacing whatever was in the variable before (and in that sense, if the
reference is "created", the previous value of the variable is
"destroyed").

What I meant was that the statement creates a new reference "o" that will
point to the same location as "str" which is where the string actually is.
Well, I would say that the statement only "creates a new reference" as
far as the compiler is concerned. That is, the reference variable
exists in the compiled code, as a local variable. The variable itself
is created as soon as you call the method containing it. Executing the
assignment simply copies a reference from one variable to another. It
doesn't really "create" anything.
>
>>In the case of a non-string object, the object is the same but we have 2
pointers to that same object. If the object changes value and both
references point to the same object, they will be the same.

Well, that would be true for a string object too, if there was any way to
actually change a string.
Right.

But what I was saying that it isn't the same as the string since if you
change the string in any way "another" object is created and then one of the
references would be pointing at the original string and the other reference
would be pointing at the new string.
But writing "if you change the string" isn't a precise way of
describing it. You can't change a string.

Again, I realize this is a subtle point, but IMHO it's important. You
may be conceptualizing the act of assigning a new string instance to
your variable as "changing the string", but that's not what you're
doing. You can't change a string, you can only replace a reference to
one string with a reference to another. The original string remains
unchanged.
>Likewise, if you assign a new reference to a reference type variable, that
doesn't affect other variables that might have referenced the same object
that variable previously referenced. For example:

object A = new object();
object B = A;

A = new object();

Right, but that is because YOU are creating a new object.
You are creating a new object in the string example as well. Granted,
the object is created as part of the applicaton's pool of string
constants, rather than being instantiated with the new operator. But
you are still creating a new object in that case too.
In the string
case, the new object is being created because you changed the string.
You didn't change the string. The original string remains unchanged.
You've simply replaced a reference to the original string with a
reference to a different string.
In a
non-string object, this would not be the case. If you said B.something =
15, both A and B would still point to the same object.
But note that in that example you're not assigning to B. You're
assigning to B.something. If there was an assignable "something"
property on the String class, you could do the same with a String.
Conversely, if you change "B.something" to "B", then assuming the
assignment is legal at all (implicit conversion, casting, etc.) you
would be replacing the _reference_ stored by the variable B rather than
changing the original instance B referenced, just like in the string
case.
>That's just like the string case. Assigning a new reference to A doesn't
change what B references. This works for _any_ reference type variable.

The thing about the string class is that assigning a new string instance
to a string type variable is the _only_ way to change the string value of
that variable. Mutable classes, you can call some method or set a
property or something like that, and that will change the instance itself,
without requiring you to assign a new instance of the class to a variable.

I realize that the distinction might seem subtle, or even pedantic. But I
think it's a very important distinction. In particular, it's very
important to understand that with respect to the code we've seen in this
thread, the string class isn't really so different from other classes.
Because it's immutable, you _have_ to write code like we've seen here,
while other classes might provide other options. But even with a mutable
class, if you write code like we've written here, it'll behave just like
the string class (except of course for the one example I showed
specifically designed to change a class instance without reassiging the
variable).

Right.

You are talking about a value type, I assume. Since you will have a value
type variable and a reference type variable.
No, the above discussion is entirely with respect to reference types.
[...]
>>It may be misleading but I think the value that gets copied does get
copied
to the heap. But in the case of an Class Object that is already on the
heap, you are copying the value from a heap location to a heap location.

I think you lost me. I'm not sure what "Class Object" refers to (maybe
something in the previously referenced web page?), but assuming it's a
class, it's a reference type and assigning the reference to the instance
to any variable just copies the reference, not the class instance itself.

I was just making the point that a value type gets copied from the stack to
the heap. But if the value type is in an object and gets boxed there, it is
already on the heap (since it is part of the object) and it is actually
getting copied from the heap to another location on the heap.
Well, a couple of points here:

First, if the value type is stored in an object, that doesn't mean it's
boxed. It's not. A value type is only boxed when it's _assigned_ to
an object reference variable. If it's _in_ an object, it's just a
plain value type.

So in that case, yes...the value when boxed is copied from one place in
the heap to another. Just as if it's copied from one class instance to
another would cause it to be copied from one place in the heap to
another.

Looking at your statement another way, if you really do want to talk
about copying an already-boxed value type to some other object
reference variable, then: if a value type is already boxed, then when
assigning that boxed instance to another object variable, no copying is
done. Once it's a reference type, the reference can be assigned at
will, with full reference type semantics. That's one of the advantages
of boxing; it really does create a reference type instance that behaves
just like any other reference type instance.

Boxing the value type is expensive, but once it's done, you get all of
the advantages of any other reference type, including being able to
assign references to other variables without having to copy all of the
data.
Not really
important just that fact that a value type is not always on the stack (if it
is part of an object). That wasn't made clear in either of the articles.
I think the second article (the slides) almost got there, but yes...I'd
agree neither was particularly clear on the matter.
>[...]
But the string is a special type of reference type (immutable) in that
>>you
can't just assign the reference to another string and assume they will
stay
the same, since any change to the string will now change the object the
reference is pointing to. Correct?

Sort of. I think I explained this above, but just to reiterate:

Knowing that the String class is immutable, you know that if two or more
variables do reference the same instance, that that instance will never
change.

In that respect it's not correct to write "any change to the string",
since there's no such thing. A string is immutable; there can be no
change to the string.

I think it is just the language here. I agree that you can't change the
string. I was just saying that if you were trying to make a change to the
string (any change) would just create another string/object with the result.
Even though it looks like the string changed - it actually didn't you are
now pointing at a new location with the changed string.
I guess my point is that long-term I think you'll have more success if
you can think more literally about what's going on when you assign a
new string reference to a string variable.

Don't think of it as "trying to make a change". If you were trying to
make a change, you'd call some method, or assign some property, in the
String class that was intended to change the instance itself. Of
course, no such method or property exists on the String class; that's
what makes it immutable. But you never "make a change" by assigning a
reference type. The only thing that can happen when assigning a
reference type is to change the reference itself.

So when you assign a string instance to a string variable, you aren't
"trying to make a change" and it could lead to problems conceptualizing
things later if you continue to think of the assignment as somehow
different from assignments of any other reference type. Assignments of
reference type variables never change the instance; you could never
"make a change" to a reference type instance with a simple assignment
to the reference type variable itself, and it's misleading to think of
doing so with a String type variable in that way.

The important thing here is this: it's practically impossible for a
human being to not be affected by the language that they use to
describe things. You may tell yourself "well, I'm saying it this way,
but I really mean something else". But as much as you may get away
with it some of the time, for most people it's impossible to get away
with it all of the time. Eventually, the way you describe the
operation is going to color your perception of what's actually going
on, and if you describe the operation imprecisely, your perception of
what's going on will be flawed and possibly lead to problems.

What kind of problems? Well, they would possibly include just having
difficulty getting a design implemented, or they could include some
actual bug. Of course, bugs caused by fundamental perception problems
are among the hardest to solve, because the code _looks_ fine to you.

Anyway, that's a very long way of saying I don't think you should ever
think about "changing a string" in .NET. Strings are immutable and
can't be changed. You also shouldn't think that assigning a reference
to a string instance to a String type variable is a way to "try to
change a string". It's not; it's a way to change the _reference_ to a
string. It would never change the string itself, whether the class was
mutable or not.

Any code you could write that _is_ actually "trying to change a string"
just won't compile. Thinking that assigning a new string instance is
an example of "trying to change a string" could lead to perception
problems with respect to the use of the String class, or it could in
fact lead to perception problems with respect to other reference types.
Either way, it can lead to problems. :)

Pete

Nov 19 '07 #19

P: n/a

"Peter Duniho" <Np*********@NnOwSlPiAnMk.comwrote in message
news:2007111910322916807-NpOeStPeAdM@NnOwSlPiAnMkcom...
On 2007-11-19 00:49:48 -0800, "tshad" <tf*@dslextreme.comsaid:
>[...]
StringType lastName = new StringType();
StringType email2 = new StringType();
lastName.Data = (object)dbReader["FirstName"];
email2.Data = (object)dbReader["Email2"];

At first I tried to cast them as string:
lastName.Data = (string)dbReader["FirstName"];
email2.Data = (string)dbReader["Email2"];

And that works fine, unless the value is null. In that case I get an
error:

"Specified cast is not valid".

Not sure why that is since a string can be null.

Based on your later discussion of this issue, it appears to me that when
you write "the value is null", it's not really null.

In spite of its name, an instance of the DBNull type is not actually a
null as far as C# is concerned. It's an actual instance of an object, and
in this case one that's incompatible with the String type. You can cast
it to Object, because you can cast anything to Object. In fact, in the
code you wrote above you don't even need the cast. You can assign
anything to Object without casting.
You're right. I don't need the (object) casting. And DBNull is really
System.DBNull which is different than null.
>
The other thing you should be careful about is the type returned by
"dbReader[]" more generally. I don't know what type that is (I do very
little database work, so forgive me if it's something obvious :) ), but
presumably it's always returning a specific type, and probably that type
is Object. This means that when value types are returned, they are
already boxed.
That is probably true. If you normally do:

string stemp;
stemp = dbReader["Name"];

You will get an compiler error that says:

Cannot implicitly convert type 'object' to 'string.

You have to:

stemp = (string)dbReader["Name"];
>[...]
Once I saw that I realized I would need to change the line before call to
the ValidateType function to:

if ((value != null) && (value != DBNull.Value))
{
_ValidateType(value);
}
and that fixes that.

Well, it fixes the validation error. Whether it's really what you want to
do, I'm not sure. For one, unless you change the IsNull property, you're
not going to deal with value types correctly. Presumably, you'd be
checking IsNull before assigning an instance of DataType, but in this case
the data will be non-null (even if it's an instance of DBNull). But
casting DBNull in the case of a value type will throw an exception, just
like as if you'd tried to cast an actual null reference to a value type.

Personally, I would fix it by converting DBNull's to actual nulls:

if (value is DBNull)
{
value = null;
}
if (value != null)
...
I agree. Then if the object is null, I can pass back DBNull.Value, since
this is mainly going to be used in a database scenario and DBNull.Value is
what is required for sending a null.

[...]
>>>4) String types are already reference types and all we are doing when
we
do
"object o = str" is create a new reference/pointer that points to the
object
on the heap.

Depends on your definition of "create". My view is that the assignment
doesn't create anything. The source and destination already exist, and
the reference is copied from one to the other.

But yes, in another sense a new copy of the reference is "created",
replacing whatever was in the variable before (and in that sense, if the
reference is "created", the previous value of the variable is
"destroyed").

What I meant was that the statement creates a new reference "o" that will
point to the same location as "str" which is where the string actually
is.

Well, I would say that the statement only "creates a new reference" as far
as the compiler is concerned. That is, the reference variable exists in
the compiled code, as a local variable. The variable itself is created as
soon as you call the method containing it. Executing the assignment
simply copies a reference from one variable to another. It doesn't really
"create" anything.
Actually, with the following:

object o = str;

Doesn't that just create another reference/pointer that points to the same
string object? So that we would now have 2 pointers (o and str) and 1
object that they both point to?

If I were to only do an "object o;", then I assume a 32 bit portion memory
is set aside that points at nothing until you use it.
>>
>>>In the case of a non-string object, the object is the same but we have
2
pointers to that same object. If the object changes value and both
references point to the same object, they will be the same.

Well, that would be true for a string object too, if there was any way
to
actually change a string.
Right.

But what I was saying that it isn't the same as the string since if you
change the string in any way "another" object is created and then one of
the
references would be pointing at the original string and the other
reference
would be pointing at the new string.

But writing "if you change the string" isn't a precise way of describing
it. You can't change a string.

Again, I realize this is a subtle point, but IMHO it's important. You may
be conceptualizing the act of assigning a new string instance to your
variable as "changing the string", but that's not what you're doing. You
can't change a string, you can only replace a reference to one string with
a reference to another. The original string remains unchanged.
I agree.

[...]
>I think it is just the language here. I agree that you can't change the
string. I was just saying that if you were trying to make a change to
the
string (any change) would just create another string/object with the
result.
Even though it looks like the string changed - it actually didn't you are
now pointing at a new location with the changed string.

I guess my point is that long-term I think you'll have more success if you
can think more literally about what's going on when you assign a new
string reference to a string variable.

Don't think of it as "trying to make a change". If you were trying to
make a change, you'd call some method, or assign some property, in the
String class that was intended to change the instance itself. Of course,
no such method or property exists on the String class; that's what makes
it immutable. But you never "make a change" by assigning a reference
type. The only thing that can happen when assigning a reference type is
to change the reference itself.

So when you assign a string instance to a string variable, you aren't
"trying to make a change" and it could lead to problems conceptualizing
things later if you continue to think of the assignment as somehow
different from assignments of any other reference type. Assignments of
reference type variables never change the instance; you could never "make
a change" to a reference type instance with a simple assignment to the
reference type variable itself, and it's misleading to think of doing so
with a String type variable in that way.

The important thing here is this: it's practically impossible for a human
being to not be affected by the language that they use to describe things.
You may tell yourself "well, I'm saying it this way, but I really mean
something else". But as much as you may get away with it some of the
time, for most people it's impossible to get away with it all of the time.
Eventually, the way you describe the operation is going to color your
perception of what's actually going on, and if you describe the operation
imprecisely, your perception of what's going on will be flawed and
possibly lead to problems.
Probably true.

Thanks,

tom
Nov 20 '07 #20

P: n/a
On 2007-11-19 21:42:13 -0800, "tshad" <tf*@dslextreme.comsaid:
[...]
Actually, with the following:

object o = str;

Doesn't that just create another reference/pointer that points to the same
string object?
Well, again, that comes down to your definition of "create". It's not
how I'd use the word, but I accept an alternative interpretation in
which you can use "create" to describe what's going on.
So that we would now have 2 pointers (o and str) and 1
object that they both point to?
That is true, and probably the most important part.
If I were to only do an "object o;", then I assume a 32 bit portion memory
is set aside that points at nothing until you use it.
Yes. And to me, that's not "creating" a pointer, nor is the assignment
"creating" a pointer. The pointer is created when you create the
object. The pointer is copied when that pointer is assigned to some
variable.

Declaring the variable "creates" a variable that can hold a reference.
Assigning the variable copies a reference to the location that was
created. But the reference itself was created already, and adding new
variables that reference the same instance doesn't create new
references, it just copies the existing one.

At least, that's how _I_ think about it. As I said, I don't find this
is something that _must_ be thought of that way. As long as you're
clear on the mechanics, I think this is a case where you can use
whatever terminology feels most comfortable to you.

Pete

Nov 20 '07 #21

This discussion thread is closed

Replies have been disabled for this discussion.