The Variant is back!!

J

Jon Davis

Hi guys!

Just wanted to let you all know that I created a Variant structure, inspired by the old VB6 days. This is written in C#, but you can build a CLR/.NET class library assembly and reference it to your liking.

' Here is an example of use:

' start with a string of "1"
Dim da As Variant = new Variant("1")

' add an integer of 2, becomes 3
da = da + 2

' add a float of 1.3, becomes 4.3
da = da + 1.3F

' add a string, becomes "4.3wow"
da = da + "wow"

' write "4.3wow"
Console.WriteLine(da)


I might actually use this puppy. :)

Anyway, here it is, source code and all, take a look and be sure to give it 5 stars if you find it useful.

http://www.planet-source-code.com/vb/scripts/showcode.asp?txtCodeId=2854&lngWId=10


Regards,
Jon Davis
 
W

W.G. Ryan eMVP

Jon:

You obviously put a lot of work into the code - but between an evil and idea
and cross posting - you're just asking for flames ;-)

--
W.G. Ryan MVP (Windows Embedded)

TiBA Solutions
www.tibasolutions.com | www.devbuzz.com | www.knowdotnet.com
Hi guys!

Just wanted to let you all know that I created a Variant structure, inspired
by the old VB6 days. This is written in C#, but you can build a CLR/.NET
class library assembly and reference it to your liking.

' Here is an example of use:

' start with a string of "1"
Dim da As Variant = new Variant("1")

' add an integer of 2, becomes 3
da = da + 2

' add a float of 1.3, becomes 4.3
da = da + 1.3F

' add a string, becomes "4.3wow"
da = da + "wow"

' write "4.3wow"
Console.WriteLine(da)


I might actually use this puppy. :)

Anyway, here it is, source code and all, take a look and be sure to give it
5 stars if you find it useful.

http://www.planet-source-code.com/vb/scripts/showcode.asp?txtCodeId=2854&lngWId=10


Regards,
Jon Davis
 
J

Jay B. Harlow [MVP - Outlook]

Jon,
Check out VB.NET 2005, as it adds support for the Overloaded Operators to
VB.NET.

http://lab.msdn.microsoft.com/vs2005/

VB.NET 2002 & 2003 do not support Overloaded Operators so your code doesn't
work per se, unless you call op_Addition, you may want to add "operator"
methods similar to what System.Decimal has, such as Decimal.Add in addition
to the overloaded operators. I normally implement overloaded operators in
terms of the "operator" methods.

You do know that you can use System.Convert.ChangeType to convert an object
from one type to another based on a System.Type variable? In fact you may
want your structure to implement System.IConvertible, and make use of the
System.Convert class to convert types for you...

Also I would seriously consider implementing a Strategy Pattern instead of
all the If statements in each method. (note Convert.ChangeType will reduce a
number of if statements, the Strategy should element almost all the rest).

Otherwise a very impressive piece of work!

Hope this helps
Jay

Hi guys!

Just wanted to let you all know that I created a Variant structure, inspired
by the old VB6 days. This is written in C#, but you can build a CLR/.NET
class library assembly and reference it to your liking.

' Here is an example of use:

' start with a string of "1"
Dim da As Variant = new Variant("1")

' add an integer of 2, becomes 3
da = da + 2

' add a float of 1.3, becomes 4.3
da = da + 1.3F

' add a string, becomes "4.3wow"
da = da + "wow"

' write "4.3wow"
Console.WriteLine(da)


I might actually use this puppy. :)

Anyway, here it is, source code and all, take a look and be sure to give it
5 stars if you find it useful.

http://www.planet-source-code.com/vb/scripts/showcode.asp?txtCodeId=2854&lngWId=10


Regards,
Jon Davis
 
J

Jon Davis

Thanks for the feedback, Jay! I'll look into modifying ConvertTo() to make
the call you suggest. I'll also look at IConvertable. As for all the If
statements, you might be right about a Strategy Pattern; consider, though,
that it was previously a select...case situation, comparing the string value
of the type's Namespace + "." + its Name properties! Yikes... hehe. :)

Thanks again,
Jon
 
J

Jon Davis

:p I actually just posted to the csharp group but then afterwards I realized
that all you wonderful VB folks might be able to appreciate it, too, so I
made a separate post (not a crosspost) here.

Jon
 
J

Jon Davis

BTW, I didn't realize that VB.NET 1.0/1.1 doesn't support overloaded
operators. I have a seriously difficult time believing that it wouldn't
support referencing types having overloaded operators in a precompiled C#
assembly, though; that would be a broken CLR, and I know Microsoft got that
much right the first time.

Jon
 
J

Jon Davis

I see that you don't like the idea of a variant.

At any rate, crossposting has always been acceptable in newsgroups as long
as it is limited to two or three groups (I've been on Usenet for a couple
decades and have created a few Usenet groups of my own), and the csharp post
was appropriate because this class was written in C#, and the vb post was
appropriate because most people using VB.NET rather than C# are VB6
veterans.

But I agree, multiposting rather than crossposting is more irksome. That's
what comes of remembering the VB crowd after the fact. So sue me.

Jon
 
J

Jon Davis

(I've been on Usenet for a couple decades ... )

erm, I mean about one decade ..

Jon
 
C

Cor Ligthert

Bill,
You obviously put a lot of work into the code - but between an evil and
idea
and cross posting - you're just asking for flames ;-)

Probably you mean multiposting, I wished that it was in that case at least
crossposting.

Cor
 
J

Jon Davis

OK I've implemented the IConvertible interface and changed the structure
accordingly, but not the operator methods and the Strategy Pattern thing
yet. Will look at those other two things next.

Jon
 
J

Jon Davis

Jay, regarding the Strategy Pattern, the problem is that type conversions
must be explicitly casted, so each and every type conversion possibility
must be explicitly referenced, as in ([totype])([fromtype])_value.
Otherwise, I would just pass ([type])_value, but it won't work that way
because the explicit custom operators for typecasting for several of the
types sees the object as System.Object as opposed to the case of
([totype])([fromtype])_value.

So a generic Strategy Pattern isn't going to achieve anything for me. This
is one of those rare exceptions; if I was doing a bunch of conditionals to
convert a VALUE, rather than TYPE, that would be different.

But please correct me if I'm forgetting something.

Jon
 
J

Jay B. Harlow [MVP - Outlook]

Jon,
Relating to IConvertible and a Select case, you could use GetTypeCode
(IConvertible.GetTypeCode & Convert.GetTypeCode) to use a Select Case based
on an integer.

Hope this helps
Jay
 
J

Jay B. Harlow [MVP - Outlook]

Jon,
Overloaded Operators are not part of the CLS (Common Language System) so
VB.NET does not implement them, just as VB.NET does not implement unsigned
integers.

As I stated VB.NET 2005 implements Overloaded Operators as both a consumer
of ones defined in C# & as a create of Overloaded Operators.

For Operator Overloading Usage Guidelines see:
http://msdn.microsoft.com/library/d...l/cpconOperatorOverloadingUsageGuidelines.asp

Hope this helps
Jay
 
J

Jay B. Harlow [MVP - Outlook]

Jon,
Jay, regarding the Strategy Pattern, the problem is that type conversions
must be explicitly casted, so each and every type conversion possibility
I realize that, which is why I suggested the Strategy Pattern. Also to limit
the select case statements in each operator.

I would base the Strategy Pattern on the type of one or both of the
arguments to the operators. Something like:

// IArithmetic represents the strategy on how to add to values.
// I suspect this should really be an abstract base class
// with overridable methods, that offer default implementation,
// such as throwing NotSupportedExceptions or similar
// for when you attempt to Divide two XmlDocument values...
private interface IArithmetic
{
object Add(object value1, object value2);
object Subtract(object value1, object value2);
object Multiply(object value1, object value2);
...
}

// IntegerArithmetic knows how to add two integers
// There would be one of these for each System.TypeCode.
private class IntegerArithmetic : IArithmetic
{
// See: http://www.yoda.arachsys.com/csharp/singleton.html
// on details on implementing Singletons.
static IArithmetic Instance = new IntegerArithmetic();

public object Add(object value1, object value2)
{
return (int)value1 + Convert.ToInt32(value2);
}
public object Subtract(object value1, object value2)
{
return (int)value1 - Convert.ToInt32(value2);
}
public object Multiply(object value1, object value2)
{
return (int)value1 * Convert.ToInt32(value2);
}
...
}

private class BooleanArithmetic : IArithmetic
...
private class SingleArithmetic : IArithmetic
...

// ArithmeticFactory returns a concrete IArithmetic object for the specified
value.
private class ArithmeticFactory
{
public static IArithmetic Create(object value)
{
// If IArithmetic handled all the type specific stuff this would be
your only "select case" statement!
switch (Convert.GetTypeCode(value))
{
case TypeCode.Boolean:
return BooleanArithmetic.Instance;
break;
case TypeCode.Single:
return SingleArithmetic.Instance;
break;
case TypeCode.Int32:
return IntergerArithmetic.Instance;
break;
...
}

}
}

// Then the operators themselves are super simple!
public static Variant operator +(Variant subjectVariant, object value)
{
return new
Variant(ArithmeticFactory.Create(subjectVariant._value).Add(subjectVariant._value,
value));
}

public static Variant operator -(Variant subjectVariant, object value)
{
return new
Variant(ArithmeticFactory.Create(subjectVariant._value).Subtract(subjectVariant._value,
value));
}

public static Variant operator *(Variant subjectVariant, object value)
{
return new
Variant(ArithmeticFactory.Create(subjectVariant._value).Multiply(subjectVariant._value,
value));
}

I would consider having ArithmeticFactory.Create accept both values & decide
which value should be elevated to the other's type. (Integer & Single
arithmetic should be done in Single not Integer) based loosely on the rules
that VB.NET follows & what COM's Variant rules followed...

Any reason that TypeMap is not implemented in terms of Convert.ChangeType
directly?

private object TypeMap(Type type)
{
return Convert.ChangeType(_value, type);
}

Also I would simply implement functions such as ToBoolean in terms of
Convert also:

public bool ToBoolean()
{
if (this._value is Boolean)
return (bool)_value;
else
return (bool)Convert.ToBoolean(_value);
}

public bool ToBoolean(IFormatProvider formatProvider)
{
return (bool)Convert.ToBoolean(_value, formatProvider);
}

I'm not sure if "_value is Boolean" is faster or slower then ".Type is
typeOf(Boolean)" it just looks cleaner to me...

I'm undecided if I would include "_value is Boolean" in ToBoolean() itself,
my initialize implementation would probably simply be:

public bool ToBoolean()
{
return (bool)Convert.ToBoolean(_value);
}

Then not worry about any performance problems, as Variant represents a
loosely typed value anyway... (read it's inefficiency is what makes it
flexibly!)

NOTE: I am implementing the conversions entirely in System.Convert as then I
am entirely consistent with the framework! Also its less code I need to
write! :)

Hope this helps
Jay




Jon Davis said:
Jay, regarding the Strategy Pattern, the problem is that type conversions
must be explicitly casted, so each and every type conversion possibility
must be explicitly referenced, as in ([totype])([fromtype])_value.
Otherwise, I would just pass ([type])_value, but it won't work that way
because the explicit custom operators for typecasting for several of the
types sees the object as System.Object as opposed to the case of
([totype])([fromtype])_value.

So a generic Strategy Pattern isn't going to achieve anything for me. This
is one of those rare exceptions; if I was doing a bunch of conditionals to
convert a VALUE, rather than TYPE, that would be different.

But please correct me if I'm forgetting something.

Jon



Jay B. Harlow said:
Jon,
Check out VB.NET 2005, as it adds support for the Overloaded Operators to
VB.NET.

http://lab.msdn.microsoft.com/vs2005/

VB.NET 2002 & 2003 do not support Overloaded Operators so your code doesn't
work per se, unless you call op_Addition, you may want to add "operator"
methods similar to what System.Decimal has, such as Decimal.Add in addition
to the overloaded operators. I normally implement overloaded operators in
terms of the "operator" methods.

You do know that you can use System.Convert.ChangeType to convert an object
from one type to another based on a System.Type variable? In fact you may
want your structure to implement System.IConvertible, and make use of the
System.Convert class to convert types for you...

Also I would seriously consider implementing a Strategy Pattern instead
of
all the If statements in each method. (note Convert.ChangeType will
reduce a
number of if statements, the Strategy should element almost all the
rest).

Otherwise a very impressive piece of work!

Hope this helps
Jay

Hi guys!

Just wanted to let you all know that I created a Variant structure, inspired
by the old VB6 days. This is written in C#, but you can build a CLR/.NET
class library assembly and reference it to your liking.

' Here is an example of use:

' start with a string of "1"
Dim da As Variant = new Variant("1")

' add an integer of 2, becomes 3
da = da + 2

' add a float of 1.3, becomes 4.3
da = da + 1.3F

' add a string, becomes "4.3wow"
da = da + "wow"

' write "4.3wow"
Console.WriteLine(da)


I might actually use this puppy. :)

Anyway, here it is, source code and all, take a look and be sure to give it
5 stars if you find it useful.

http://www.planet-source-code.com/vb/scripts/showcode.asp?txtCodeId=2854&lngWId=10


Regards,
Jon Davis
 
W

W.G. Ryan eMVP

I did mean multi-posting but as Jon points out, multiposting is perfectly
acceptable and he's been posting for multiple decades so I guess I'm wrong
about this ;-)
 
W

W.G. Ryan eMVP

Wouldn't cross posting accomplish the same thing without having two
different branches of comments. At any rate it was just a suggestion, I
don't pretend to be the etiquette police but I can tell you that many around
here find multi-posting to be an annoyance.

At the risk of sounding combative, I'm just curious, where did you come up
with this <<and the vb post was
appropriate because most people using VB.NET rather than C# are VB6
veterans.>>.
 
J

Jon Davis

Jay,
public object Add(object value1, object value2)
{
return (int)value1 + Convert.ToInt32(value2);
}



My goal was not just wire up a universal overload map to
System.Convert.ChangeType(), nor do I always presume that I am working with
numbers. There are many features that I wanted to implement that .NET simply
does not implement on its own. The Boolean scenario is a classic example;
Convert.ChangeType() simply does not do what my CBln does. As a matter of
fact, bool.Parse() kept locking up my test console for some two seconds!
Proper conversion to and from numerics and non-numerics are evaluated in all
instances.

As for arithmetic operator overloads, I am certain there is a lot of
clean-up I can still do, but right now--tonight, as opposed to tomorrow
:)--I'm tentatively content; after some changes made earlier today (before
reading your post) I'm now converting everything to a double, doing the
arithmetic, and then casting back to an appropriate type.

As for ToTypeMap(), ignore it, it's private; I refactored the block of code
into a method because I call it twice in ToType(), depending on the presence
of IFormatProvider.

I do appreciate your examples and suggestions, and I will continue to ponder
on them.

Thanks again,
Jon



Jay B. Harlow said:
Jon,
Jay, regarding the Strategy Pattern, the problem is that type conversions
must be explicitly casted, so each and every type conversion possibility
I realize that, which is why I suggested the Strategy Pattern. Also to limit
the select case statements in each operator.

I would base the Strategy Pattern on the type of one or both of the
arguments to the operators. Something like:

// IArithmetic represents the strategy on how to add to values.
// I suspect this should really be an abstract base class
// with overridable methods, that offer default implementation,
// such as throwing NotSupportedExceptions or similar
// for when you attempt to Divide two XmlDocument values...
private interface IArithmetic
{
object Add(object value1, object value2);
object Subtract(object value1, object value2);
object Multiply(object value1, object value2);
...
}

// IntegerArithmetic knows how to add two integers
// There would be one of these for each System.TypeCode.
private class IntegerArithmetic : IArithmetic
{
// See: http://www.yoda.arachsys.com/csharp/singleton.html
// on details on implementing Singletons.
static IArithmetic Instance = new IntegerArithmetic();

public object Add(object value1, object value2)
{
return (int)value1 + Convert.ToInt32(value2);
}
public object Subtract(object value1, object value2)
{
return (int)value1 - Convert.ToInt32(value2);
}
public object Multiply(object value1, object value2)
{
return (int)value1 * Convert.ToInt32(value2);
}
...
}

private class BooleanArithmetic : IArithmetic
...
private class SingleArithmetic : IArithmetic
...

// ArithmeticFactory returns a concrete IArithmetic object for the specified
value.
private class ArithmeticFactory
{
public static IArithmetic Create(object value)
{
// If IArithmetic handled all the type specific stuff this would be
your only "select case" statement!
switch (Convert.GetTypeCode(value))
{
case TypeCode.Boolean:
return BooleanArithmetic.Instance;
break;
case TypeCode.Single:
return SingleArithmetic.Instance;
break;
case TypeCode.Int32:
return IntergerArithmetic.Instance;
break;
...
}

}
}

// Then the operators themselves are super simple!
public static Variant operator +(Variant subjectVariant, object value)
{
return new
Variant(ArithmeticFactory.Create(subjectVariant._value).Add(subjectVariant._
value,
value));
}

public static Variant operator -(Variant subjectVariant, object value)
{
return new
Variant(ArithmeticFactory.Create(subjectVariant._value).Subtract(subjectVari
ant._value,
value));
}

public static Variant operator *(Variant subjectVariant, object value)
{
return new
Variant(ArithmeticFactory.Create(subjectVariant._value).Multiply(subjectVari
ant._value,
value));
}

I would consider having ArithmeticFactory.Create accept both values & decide
which value should be elevated to the other's type. (Integer & Single
arithmetic should be done in Single not Integer) based loosely on the rules
that VB.NET follows & what COM's Variant rules followed...

Any reason that TypeMap is not implemented in terms of Convert.ChangeType
directly?

private object TypeMap(Type type)
{
return Convert.ChangeType(_value, type);
}

Also I would simply implement functions such as ToBoolean in terms of
Convert also:

public bool ToBoolean()
{
if (this._value is Boolean)
return (bool)_value;
else
return (bool)Convert.ToBoolean(_value);
}

public bool ToBoolean(IFormatProvider formatProvider)
{
return (bool)Convert.ToBoolean(_value, formatProvider);
}

I'm not sure if "_value is Boolean" is faster or slower then ".Type is
typeOf(Boolean)" it just looks cleaner to me...

I'm undecided if I would include "_value is Boolean" in ToBoolean() itself,
my initialize implementation would probably simply be:

public bool ToBoolean()
{
return (bool)Convert.ToBoolean(_value);
}

Then not worry about any performance problems, as Variant represents a
loosely typed value anyway... (read it's inefficiency is what makes it
flexibly!)

NOTE: I am implementing the conversions entirely in System.Convert as then I
am entirely consistent with the framework! Also its less code I need to
write! :)

Hope this helps
Jay




Jon Davis said:
Jay, regarding the Strategy Pattern, the problem is that type conversions
must be explicitly casted, so each and every type conversion possibility
must be explicitly referenced, as in ([totype])([fromtype])_value.
Otherwise, I would just pass ([type])_value, but it won't work that way
because the explicit custom operators for typecasting for several of the
types sees the object as System.Object as opposed to the case of
([totype])([fromtype])_value.

So a generic Strategy Pattern isn't going to achieve anything for me. This
is one of those rare exceptions; if I was doing a bunch of conditionals to
convert a VALUE, rather than TYPE, that would be different.

But please correct me if I'm forgetting something.

Jon



Jon,
Check out VB.NET 2005, as it adds support for the Overloaded Operators to
VB.NET.

http://lab.msdn.microsoft.com/vs2005/

VB.NET 2002 & 2003 do not support Overloaded Operators so your code doesn't
work per se, unless you call op_Addition, you may want to add "operator"
methods similar to what System.Decimal has, such as Decimal.Add in addition
to the overloaded operators. I normally implement overloaded operators in
terms of the "operator" methods.

You do know that you can use System.Convert.ChangeType to convert an object
from one type to another based on a System.Type variable? In fact you may
want your structure to implement System.IConvertible, and make use of the
System.Convert class to convert types for you...

Also I would seriously consider implementing a Strategy Pattern instead
of
all the If statements in each method. (note Convert.ChangeType will
reduce a
number of if statements, the Strategy should element almost all the
rest).

Otherwise a very impressive piece of work!

Hope this helps
Jay

Hi guys!

Just wanted to let you all know that I created a Variant structure, inspired
by the old VB6 days. This is written in C#, but you can build a CLR/.NET
class library assembly and reference it to your liking.

' Here is an example of use:

' start with a string of "1"
Dim da As Variant = new Variant("1")

' add an integer of 2, becomes 3
da = da + 2

' add a float of 1.3, becomes 4.3
da = da + 1.3F

' add a string, becomes "4.3wow"
da = da + "wow"

' write "4.3wow"
Console.WriteLine(da)


I might actually use this puppy. :)

Anyway, here it is, source code and all, take a look and be sure to
give
it
5 stars if you find it useful.
http://www.planet-source-code.com/vb/scripts/showcode.asp?txtCodeId=2854&lngWId=10
Regards,
Jon Davis
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top