Home > Archive > C# > December 2005 > Create Immutable Type Like string
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Create Immutable Type Like string
|
|
| JoSkillz 2005-12-02, 9:56 pm |
| I was wondering if anyone knew of a way to create an immutable type
object where I don't have to reference an accessor to gain access to
value I would like the object to behave as follows:
Unit unitX = 23;
public int ConvertToInt(Unit unitsToConvert)
{
// do something with the unit.
}
I am just trying to create a type specfic syntax. I am trying to avoid
creating a struct and adding readonly accessor to it, to gain access to
the value I want to store.
Any help you can give me will be greatly appreciated.
| |
| Bruce Wood 2005-12-02, 9:56 pm |
| What exactly do you want Unit to do? It is possible to do what you're
asking, but it may not be appropriate.
Creating an immutable reference type is easy: just don't provide any
"set" accessors: field values are set on the constructor and then
cannot be altered. Depending upon what you want "Unit" to do, it might
be better off as a struct, where you can do exactly the same thing.
In order to have a "principal attribute" that you can assign or read
without specifying a property name, all you have to do is define
implicit conversions from your "Unit" type to another, appropriate type
in both directions. If you define implicit conversions from, say, Unit
to int, and int to Unit, then when you say:
Unit unitX = 23;
the compiler will simply generate code to call your implicit conversion
method. Now, I don't know if this works with reference types. I've done
it with value types and it works just fine. For example, I have a
Fraction value type, and I can say:
Fraction f = new Fraction(2, 5, 16); // 2 5/16ths
decimal x = f;
and x gets the value 2.3125, just as you would expect. I don't allow
implicit conversion in the opposite direction because of the problem of
determining a denominator, but I'm sure it would work.
As I said, Fraction is a struct, not a class, so I don't know the
implications of doing something like this with a reference type.
Personally, I would find that rather odd and would avoid it.
| |
| JoSkillz 2005-12-02, 9:56 pm |
| Thanks Bruce,
In a way you answered my question.
My question was revolving around an issue I have within my domain.
I am working on a XP management tool for internal use within my
company. I know there are plenty of commercial and open source
products that do this already but I want to learn how to take advantage
of 2.0=E2=80=99s new features.
XP uses a term for measuring level of effort called a =E2=80=9CUnit=E2=80=
=9D
internally within the domain this is stored as a decimal. Now
traditional project management as we all know is measured in person
hours and days which coincidently are decimal values as well; I have
come up with and algorithm to correlate a measure of =E2=80=9CUnit=E2=80=9D=
to
=E2=80=9CPerson Hours.=E2=80=9D
I wanted to try to AVOID the following syntax:
Unit unitX =3D new Unit(1.5);
Hours hoursX =3D new Hours(Hours.ConvertToUnits(unitX.Value));
Console.WriteLine(hoursX.Value.ToString);
public struct Unit
{
private readonly decimal worth;
public Unit(decimal unitWorth)
{
this.worth =3D unitWorth;
}
public decimal Value
{
get { return this.worth; }
}
public static double ConvertToHours()
{
}
}
public struct Hours
{
private readonly decimal worth;
public Hours(decimal hourlyWorth)
{
this.worth =3D hourlyWorth;
}
public decimal Value
{
get { return this.worth; }
}
public static double ConvertToUnits()
{
}
}
I wanted it to read more like this.
Unit unitX =3D 1.5;
Hours hoursX =3D Hours.ConvertToUnits(unitX.Value);
Console.WriteLine(hoursX.ToString);
As you can see this code is more readable since the =E2=80=9CValue=E2=80=9D
accessor is implicit of the type. If I have to do it the former way I
will. Just being picky that is all =EF=81=8A
Thanks for all your help though.
| |
| Bruce Wood 2005-12-02, 9:56 pm |
| No, you can do exactly what you want to, and it's even a good idea,
since you're dealing with structs, not classes. I was worried that you
were going to try to do this with a reference type, since you mentioned
String.
All you have to do is declare, in Unit.cs, implicit conversion
operators from decimal to Unit:
public static implicit operator Unit(decimal valueToConvert)
{
return new Unit(valueToConvert);
}
This will allow you to say:
Unit unitX = 1.5;
and the compiler will automatically insert a call to your conversion
operator. As well, you can say
public static implicit operator decimal(Unit unitValue)
{
return unitValue.Value;
}
and if you say:
decimal val = unitX;
the compiler will allow it and insert a call to your conversion method.
As you can well imagine, you can do the same thing from Hours to Units:
public static implicit operator Unit (Hours hoursValue)
{
.... whatever ....
}
You couldn't implicitly go the other way, of course, because you
wouldn't have an "hourly worth" value to work with.
| |
| JoSkillz 2005-12-05, 7:03 pm |
| You rock! That is exactly what I was looking for!
Question is "static implicit operator" a 2.0 fearue only? I had never
heard of this till now.
| |
| Bruce Wood 2005-12-05, 7:03 pm |
| No, I'm using 1.1. I don't know if it was in 1.0, but it's definitely
in 1.1.
| |
| Bruce Wood 2005-12-05, 7:03 pm |
| By the way (just for your information), you can also declare cast
operators as "static explicit operator", which requires the caller to
make an explicit cast:
public static explicit operator Unit (Hours hoursValue)
{
... whatever ...
}
which would require the caller to say:
Hours hoursValue = ...
Unit myUnit = (Unit)hoursValue;
while
Unit myUnit = hoursValue;
will fail with a compiler error.
This is useful in cases in which there will be a loss of information in
the cast, and you want your caller to explicitly "give permission" to
perform the cast and ignore any adverse effects.
|
|
|
|
|