13

Why does this work in VB.Net:

Dim ClipboardStream As New StreamReader(
    CType(ClipboardData.GetData(DataFormats.CommaSeparatedValue), Stream))

But this is throwing an error in C#:

Stream is a Type, which is not valid in the current context

ClipboardStream = new StreamReader(Convert.ChangeType(
    ClipboardData.GetData(DataFormats.CommaSeparatedValue), Stream));

To be honest, I'm not 100% clued up on converting types, I've only ever used them in code snippets and now I'm trying to convert a simple VB code snippet to a C# version...

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
jamheadart
  • 5,047
  • 4
  • 32
  • 63

4 Answers4

14

ChangeType accepts a Type as the second parameter, so you should write typeof(Stream). typeof(Stream) evaluates to a Type instance representing the type Stream. Just using Stream there does not work because it does not evaluate to a value. It's not an expression.

Anyway, you shouldn't be using ChangeType here anyway, you should cast, which is the C# equivalent of CType:

 ClipboardStream = new StreamReader((Stream)ClipboardData.GetData(DataFormats.CommaSeparatedValue));
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • 1
    No, C#'s cast is equivalent to VB's `DirectCast`. `CType` potentially performs conversion between convertible types. For example `var myString = (string)myInt` doesn't even compile, neither does `myInt as string`, but `Ctype(myInt, String)` is perfectly legal and works. – Teejay Sep 20 '18 at 14:16
8

CType is a compiler function in VB.Net. It allows its second argument to be an expression that yields a type name. You cannot write functions like that yourself in either VB or C#.

The C# using Convert would be, as Patrick says, be:

ClipboardStream = new StreamReader(Convert.ChangeType(
ClipboardData.GetData(DataFormats.CommaSeparatedValue),typeof(Stream)));

But this code is closer to if this had been written in VB:

ClipboardStream = New StreamReader(Convert.ChangeType( _
ClipboardData.GetData(DataFormats.CommaSeparatedValue),GetType(Stream)))

CType in VB is a lot closer to a cast in C# (e.g. (Stream)... rather than CType(..., Stream))

adjan
  • 13,371
  • 2
  • 31
  • 48
Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • @PatrickHofman - It's the VB equivalent of `typeof`. Working on improving the wording to indicate that second sample *is* VB. – Damien_The_Unbeliever May 01 '18 at 07:17
  • I don't have an IDE to verify right now, but `GetType()` should be only available right side of a comparison or assignment. – Jimi May 01 '18 at 07:38
  • @Jimi - check the examples (remember to switch to VB) - [Convert.ChangeType](https://msdn.microsoft.com/en-us/library/dtb69x08(v=vs.110).aspx#Examples) – Damien_The_Unbeliever May 01 '18 at 07:46
  • Well, yes, `Convert.ChangeType()` accepts it. But, then, what kind of type `ClipboardStream` would be? It's a narrowing convertion (if I'm not mistaken), that probably even with Option Strict off is invalid. I'll check it out. – Jimi May 01 '18 at 08:18
  • But, I was assuming that `ClipboardData.GetData()`, given its parameter, is equivalen to `Clipboard.GetData()`. Which might not be. – Jimi May 01 '18 at 08:32
  • Is `CType` more of a compiler function than `typeof`? – Zev Spitz May 01 '18 at 15:48
7

Because passing in a type in C# is different than it is in VB.NET. You should use typeof(Stream):

ClipboardStream = new StreamReader
                    ( Convert.ChangeType
                        ( ClipboardData.GetData(DataFormats.CommaSeparatedValue)
                        , typeof(Stream)
                        )
                    );

In this case however, a simple cast would be better:

ClipboardStream = new StreamReader
                    ( (Stream)ClipboardData.GetData(DataFormats.CommaSeparatedValue)
                    );
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • Thanks. Was just looking around and saw the `typeof` on a few code examples on MSDN and was about to try it. I don't understand casting either, but it works perfectly so I'll use that and try to do some reading on it ASAP :) – jamheadart May 01 '18 at 07:09
  • This is incorrect. If you were to use `Convert.ChangeType` in VB.NET you also couldn't pass in a type name; you'd have to pass in a type instance. Like C#'s `typeof` operator, which gets a `Type` instance from a type name, VB.NET has the `GetType` operator: `Convert.ChangeType(ClipboardData.GetData(DataFormats.CommaSeparatedValue), GetType(Stream))`. – Zev Spitz May 01 '18 at 15:46
5

Convert.ChangeType expects a Type argument in its second parameter. To obtain the Type instance from a variable, call the GetType() method or use the typeof operator:

ClipboardStream = new StreamReader(Convert.ChangeType(
ClipboardData.GetData(DataFormats.CommaSeparatedValue), Stream.GetType()));


ClipboardStream = new StreamReader(Convert.ChangeType(
ClipboardData.GetData(DataFormats.CommaSeparatedValue), typeof(Stream)));

Another way (imo the preferred way) is to use the casting operator

ClipboardStream = new StreamReader((Stream)ClipboardData.GetData(DataFormats.CommaSeparatedValue));
adjan
  • 13,371
  • 2
  • 31
  • 48