Question

Here's what I want to do:

XmlWriter writer = XmlWriter.Create(
    (string.IsNullOrEmpty(outfile) ? Console.Out : outfile)
);

This does not compile, however, giving the error "Type of conditional expression cannot be determined because there is no implicit conversion between 'System.IO.TextWriter' and 'string'". The above code is a simplification of the following:

XmlWriter writer;

if (string.IsNullOrEmpty(outfile))
{
    writer = XmlWriter.Create(Console.Out); // Constructor takes TextWriter
}
else
{
    writer = XmlWriter.Create(outfile); // Constructor takes string
}

These two calls to Create are perfectly valid, and this compiles. Is there a way to make this more compact, like I was trying to do with my inline test?

It doesn't make sense to me that what I want doesn't work. Mentally thinking through this, it seems like the compiler would evaluate string.IsNullOrEmpty(outfile) to determine which case to take:

  • If the condition were true, it would go with Console.Out, and then see that it needs to polymorphically choose the version of XmlWriter.Create that takes a TextWriter.
  • If the condition were false, it would go with outfile, and then see that it needs to polymorphically choose the version of XmlWriter.Create that takes a string.

Has programming in ML warped my brain?

Was it helpful?

Solution

The reason you can't do that is because the compiler must choose which overload of Create to use at compile time - your approach would require it to be done at runtime. The shortest you can make it is probably:

XmlWriter writer = String.IsNullOrEmpty(outfile)
    ? XmlWriter.Create(Console.Out)
    : XmlWriter.Create(outfile);

OTHER TIPS

Everyone seems to be suggesting the following:

XmlWriter writer = String.IsNullOrEmpty(outfile)
    ? XmlWriter.Create(Console.Out)
    : XmlWriter.Create(outfile);

However, this is also doable:

XmlWriter writer = XmlWriter.Create(string.IsNullOrEmpty(outfile)
    ? Console.Out : new StreamWriter(outfile));

The latter is closer to your original attempt and, IMO, more compact.

The C# compiler chooses a method to execute statically during compilation. The IL that gets generated when you compile is a reference to a specific method. The polymorphism part comes in at runtime when it chooses what implementation of that specific function to execute.

Your ?: statement is evaluated at runtime and as such the compiler can't figure out which method to execute.

Change to this and it'll work.

XmlWriter writer = string.IsNullOrEmpty(outfile) ? 
    XmlWriter.Create(Console.Out) :
    XmlWriter.Create(outfile);

The problem is that you can't determine at compile time what

(string.IsNullOrEmpty(outfile) ? Console.Out : outfile)

should return. Is it going to be a string or is it going to be a TextWriter? That can only be determined at run time, hence the compile error because the ? operator has to be resolved at compile time.

The best you can get out of it would probably be:

XmlWriter writer = string.IsNullOrEmpty(outfile)
    ? XmlWriter.Create(Console.Out)
    : XmlWriter.Create(outfile);

A couple of things are happening here.

First, the "exception" is occurring because of The Ternary Operator (tm), not because of where you're using it. The problem is because you've got a single expression that is trying to return two different types that can't be resolved to a single, common base type (other than object).

Further, your constructor overloads probably take two completely different types that aren't related in any way whatsoever. The C# compiler is very, very smart, but it's not quite that smart.

No, you have to make two separate calls, as they are two separate constructors.

Which overload to call is determined at compile time, so you can't select a data type at runtime to call different overloads.

Also, the conditional operator can only return a single data type, you can't have it return different data types depending on the choise.

C# is statically typed all the polymorphism magic is happening compile time. And the type of your conditional expression is not known at the compile time.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top