Problem with out parameters

G

Gianluca

Hi,

I want to make a class that acts like an "object factory", that
creates objects all inherited from a root class called MyBaseObject.
To create objects I want to use a method in which I pass in the first
parameter the object type I want to create, and in the second
parameter (an output parameter) the reference to the object created.

So, the method is declared like this:
public int GetObject(MyObjectTypes type, out MyBaseObject obj)

Suppose I have a class MyObject1 inherited from MyBaseObject.

In the client code that uses the GetObject method I want to do
something like this:

.... other lines of code ...
MyObject1 newObj;
Factory.GetObject(MyObjcectType.Object1, out newObj);
.... other lines of code ...

Using the code above, I get the following error at compilation time:
'argument 2: cannot convert from out MyObject1 to out MyBaseObject'.

I use this code to avoid the problem:

.... other lines of code ...
MyObject1 newObj;
MyBaseObject temp;

Factory.GetObject(MyObjcectType.Object1, out temp);
newObj = (MyObject1) temp;
.... other lines of code ...

Is there a way to force the c# compiler to accept the first version of
my code?

Thanks in advance for any suggestion

Bye
Gianluca
 
J

Jon Skeet [C# MVP]

Gianluca said:
I want to make a class that acts like an "object factory", that
creates objects all inherited from a root class called MyBaseObject.
To create objects I want to use a method in which I pass in the first
parameter the object type I want to create, and in the second
parameter (an output parameter) the reference to the object created.

So, the method is declared like this:
public int GetObject(MyObjectTypes type, out MyBaseObject obj)

What's it returning, and is it actually important? (You're ignoring it
in the calling code example you've given.) It seems quite odd to me
that a method called GetObject doesn't return an object of any
description in its normal returned value.

I suggest you change the signature to

public MyBaseObject GetObject (MyObjectTypes type)

That way you can just do:

MyObject1 newObj = (MyObject1) Factory.GetObject(MyObjectType.Object1);
 
B

Bruce Wood

Is there a way to force the c# compiler to accept the first version
of my code?

As Mattias said, "No," and here is why.

Your method declares that it is returning a MyBaseObject in the out
variable, which means that it could return an actual MyBaseObject or
any object of a type derived from MyBaseObject, such as a MyObject1.

However, the calling method has no way of knowing what will be
returned. If it were to allow you to pass a MyObject1 as the out
argument, then the method could conceivably return an object of type
MyBaseObject, or MyObject2, or some other thing, and you would end up
breaking type safety. You would have a MyObject1 variable referring to
(pointing to) an object of a different type. Very bad!

As such, the compiler requires you to perform a specific act--a
cast--to assure it that you know the thing being returned is really a
MyObject1 and not anything else.

I suppose that the language designers could come up with some
nomenclature for a cast-and-out-argument all rolled into one, but it
seems unlikely that you'd often need something like that.

You can, of course, get around this by doing this:

public class Factory
{
public static void GetObject(MyObjectType type, out MyBaseObject
result)
{
...
}

public static void GetObject(MyObjectType type, out MyObject1 result)
{
MyBaseObject temp;
GetObject(type, out temp);
result = (MyObject1)temp;
}
}

....but then the "object type" argument seems superfluous, doesn't it,
so you could simply recode it like this:

public static void GetObject(out MyObject1 result)
{
MyBaseObject temp;
GetObject(MyObjectType.Object1, out temp);
result = (MyObject1)temp;
}

Note that this works only if you use "out" parameters... it won't work
with function results, because all of the methods would have the same
signature.

It also someone bastardizes the Factory pattern, because it means that
for every new derived type you implement, you have to create a new
nethod signature in the Factory. However, it does give you a more
convenient notation for calling the factory method.
 
G

Gianluca

[...]

Thanks to all for your help.
I know that what I'm trying to do is possibile in VB.NET, so I thought
that I could do it in that way also in C#.

Anyway, I will take into consideration your suggestions.

Bye
 

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