Using a structure as a property in a class gives error when accessing properties of structure

D

D Witherspoon

I have a Structure I have created and am using it as a Public Property of a class. Here is the property.

------------------------------------------------------

Dim _MyID As SInteger

Public Property MyID() As SInteger

Get

Return _MyID

End Get

Set(ByVal Value As SInteger)

_MyID = Value

End Set

End Property



Here is the structure

--------------------------------------------------------

Public Structure SInteger



Private mi_Value As Integer

Private mb_IsNull As Boolean



Public Property Value() As Integer

Get

Return mi_Value

End Get

Set(ByVal Value As Integer)

mi_Value = Value

End Set

End Property



Public Property IsNull() As Boolean

Get

Return mb_IsNull

End Get

Set(ByVal Value As Boolean)

mb_IsNull = Value

End Set

End Property



End Structure

So....

In the class when i want to set the value of the Value or isNull property of the structure ...

MyID.Value = 5

I get an error: Expression is a value and therefore cannot be the target of an assignment.

But if I use

_MyID.Value=5 it works



What's the deal here???
 
M

Mattias Sjögren

What's the deal here???

Since SInteger is a structure, the property will return a copy of the
_MyID value. If you were allowed to do this assignment, it would only
affect this temporary copy, and not the private _MyID variable. Since
that would be pretty useless and probably not what you want, the
compiler doesn't allow it.



Mattias
 
D

D Witherspoon

Thanks,

Is there a way to access the property ByRef then?

Or would I have better results using a class?
 
R

Rodger Constandse

The problem is that SInteger is a value type, so when you write

MyID.Value = 5

The MyID call is returning a copy of the _MyID variable (not the _MyID variable
itself) as a temporary value. Any assignment to this temporary value is
meaningless because it is never used again.

Think of it like this:

SInteger tempCopy = MyID;
tempCopy.Value = 5;

I think the compiler is just trying to prevent you from erroneously believing
that you would actually be changing the value of _MyID with this expression when
you really would not be. That error message is probably preventing a ton of bugs.

What you would need to do is something like this:

MyID = new SInteger(5);

which assigns a new SInteger value to the MyID property.

When you use _MyID you are dealing with the variable directly so there is no
temporary copy involved.

The error message you get from the C# compiler is:
"Cannot modify the return value of 'your property name' because it is not a
variable"

Hope this helps
 
J

Jon Skeet [C# MVP]

D Witherspoon said:
Is there a way to access the property ByRef then?

Or would I have better results using a class?

Yes, you'd have better results using a class. Creating your own value
type should be a very rare event. Creating your own *mutable* value
type should be even rarer.
 
R

Rodger Constandse

You have to be careful when using a class for something like this because you
could end up with two objects that have a reference to the same value. For example,

class BusinessObject
{
private SInteger _MyID;

public SInteger MyID
{
get { return _MyID; }
set { _MyID = value; }
}
}

BusinessObject b1 = new BusinessObject();
BusinessObject b2 = new BusinessObject();

b1.MyID.Value = 5;

so far so good, it now allows you to do this if you define SInteger as a class
because MyID property returns a reference.

However, if you do this:

b2.MyID = b1.MyID;

The _MyID member of both b1 and b2 point to the same object, probably not what
you want.

b2.MyID.Value = 7;

Now b1.MyID.Value and b2.MyID.Value return 7.

You might be better off keeping SInteger as a value type and either assign
values directly:

b1.MyID = new SInteger(5);

or define an implicit conversion between int type and SInteger

public struct SInteger
{
public SInteger(int val)
{
_value = val;
}

// implicit conversion from int to SInteger
public static implicit operator SInteger(int val)
{
return new SInteger(val);
}

public int Value
{
...
}
private int _value;
}

which would allow you to say something like

b1.MyID = 5;

with the compiler doing the implicit conversion for you.

Hope this helps
 
J

Jon Skeet [C# MVP]

Rodger Constandse said:
You have to be careful when using a class for something like this because you
could end up with two objects that have a reference to the same value.

Yes, you certainly need to be careful, and understand what a reference
type is, and how to use them appropriately - but I think that's almost
always better than creating your own value type.
 

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