Code calls method with wrong signature (object vs object[])

  • Thread starter Thread starter LordHog
  • Start date Start date
L

LordHog

Hello all,

I recently ran into a strange behavior which I don't understand. I
have two 'Add' method which a slightly different signature which they
look like

public void Add( string varName, ScriptVarType type, object value )
public void Add( string varName, ScriptVarType type, object[] values
)

Then in another part of the source base I have the following
declaration

private void Extract( ... )
{
byte[] byteElements;

...

// Where all arguments are assigned before the call is made
ScriptVars.Add( groupsRegEx[1].Value, type, byteElements );
}

The strange item which I don't understand is that instead of call the
method that accepts an array of objects the code is calling the method
where the signature only accepts a single object. Can someone explain
why this is? My guess is since object is the base class of most items
it is also the base class for arrays. Any explanation will be
appreciated. For the time being I will just end up change the method
names to force call to the correct method istead of relying on the
compiler looking at the signature. Thanks

Mark
 
Mark,

The problem here is that arrays are not inherently polymorphic. So, as
a result, the compiler tries to match up the call with the appropriate
function, it sees that byte[] does not cast down to object[], but it does
cast down to object, and that's why the call is made.

You might want to try defining the parameter with the object array as
System.Array, and see if that works.

Hope this helps.
 
Two simply workarounds leap to mind:
// 1: since Array is the base of all array implementations
public void Add( string varName, ScriptVarType type, Array values) {}

// 2: (2.0 only) generics;
// note you generally won't have to specify T
// when calling - i.e. declare an int[] vals and call Add(blah, vals);
public void Add<T>( string varName, ScriptVarType type, T[] values) {}

Marc
 
The strange item which I don't understand is that instead of call the
method that accepts an array of objects the code is calling the method
where the signature only accepts a single object. Can someone explain
why this is? My guess is since object is the base class of most items
it is also the base class for arrays. Any explanation will be
appreciated. For the time being I will just end up change the method
names to force call to the correct method istead of relying on the
compiler looking at the signature.

Changing the method names won't help you, as a byte[] isn't an
object[]. The problem is that while *arrays of reference types* are
covariant, arrays of value types aren't. For instance:

string[] stringArray = new string[10];
object[] objectArray = stringArray; // Fine

but

byte[] byteArray = new byte[10];
int[] intArray = byteArray; // No conversion available
object[] objectArray = byteArray; // No conversion available

The other posts give suggested solutions.

Jon
 
Nicholas,

Thanks for the information as I didn't realize this until now.
Instead of passing in an array of byte, short or int I boxed them into
an array of objects them unboxed them within the called method. I don't
like this implementation as it is not all that elegant, but it will do
for now until I find a better approach.

Mark


Mark,

The problem here is that arrays are not inherently polymorphic. So, as
a result, the compiler tries to match up the call with the appropriate
function, it sees that byte[] does not cast down to object[], but it does
cast down to object, and that's why the call is made.

You might want to try defining the parameter with the object array as
System.Array, and see if that works.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Hello all,

I recently ran into a strange behavior which I don't understand. I
have two 'Add' method which a slightly different signature which they
look like

public void Add( string varName, ScriptVarType type, object value )
public void Add( string varName, ScriptVarType type, object[] values
)

Then in another part of the source base I have the following
declaration

private void Extract( ... )
{
byte[] byteElements;

...

// Where all arguments are assigned before the call is made
ScriptVars.Add( groupsRegEx[1].Value, type, byteElements );
}

The strange item which I don't understand is that instead of call the
method that accepts an array of objects the code is calling the method
where the signature only accepts a single object. Can someone explain
why this is? My guess is since object is the base class of most items
it is also the base class for arrays. Any explanation will be
appreciated. For the time being I will just end up change the method
names to force call to the correct method istead of relying on the
compiler looking at the signature. Thanks

Mark
 
Marc said:
Two simply workarounds leap to mind:
// 1: since Array is the base of all array implementations
public void Add( string varName, ScriptVarType type, Array values) {}

// 2: (2.0 only) generics;
// note you generally won't have to specify T
// when calling - i.e. declare an int[] vals and call Add(blah, vals);
public void Add<T>( string varName, ScriptVarType type, T[] values) {}

Marc


Marc,

I think the first solution you have provided provides me with a nice
approach and it does appear to work well. I would use the second
approach, but as in my first implementation of using generics for this
project I had to scrap it as the variable is not known at compile time
and only as a script file is parsed, thus I always get "Cannot convert
type 'T[]' to 'byte[]' or other data types.

Is there a nice way of dealing with this?

So if I have my method signature that looks like

public void Add<T>( string varName, ScriptVarType type, T[] values )

then depending upon the type of variable that is determined at run-time
I need to cast it to a byte, short, int, float or string (etc..). I
could provide a signature for each variable type, but I was hoping to
have one method that accepts the arguments and cast them to the
appropriate type. I am not quite sure what the best approach is. I
was also having issues using bitwise operation (masking) of generics as
I would always get compiler errors. I really was hoping to use
generics, but I ran into problems using them when I had value and ref
types mixed.

Mark
 
then depending upon the type of variable that is determined at run-time
I need to cast it to a byte, short, int, float or string (etc..).

Generics is not the solution to every problem, however, if you can elaborate
on what you are trying to do (perhaps a little pseudocode as to why you need
to know the specific types), then I might be able to help. The framework
provides a number of handy interfaces (which framework objects supprt) and
helper classes to assist with generics, such as IEquatable<T>,
IComparable<T>, EqualityComparer<T>.Default, etc.

Reflection is an option, but could be just as messy, and I don't like using
it if there is a perfectly good compile-time alternative available to me...
I was also having issues using bitwise operation (masking) of
generics as I would always get compiler errors.

What with things like ints, enums, etc? Yup, that's a right royal pain.
Can't be done neatly via generics AFAIK.
I ran into problems using them when I had value and ref
types mixed.

Anything specific? Note things like default(T), new(), and the : class / :
struct constraints may be of use. But again, generics is not a "fixes
everything ever" kind of thing. It helps though.

Marc
 

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

Back
Top