20

I have the following (simplified) method:

private static string GetStringFromValue<T>(T val)
{
    if (typeof(T) == typeof(DateTime))
    {
        return string.Format("{0}", ((DateTime)val).Year.ToString("0000"));
    }
    return string.Empty;
}

At the cast "(DateTime)val" I get the following error:

Cannot cast expression of Type 'T' to type 'DateTime'

What can I do to access the Year property of the DateTime parameter?

UPDATE: Thank you for all your very fast answers. This method (and method name) is really (!) simplified to show exactly my problem and to let everyone just copy&paste it into his own visual studio. It is just that I wanted to add some Type specific values if the type is a DateTime. Beside that 99% of the method is the same.

Chris
  • 4,325
  • 11
  • 51
  • 70
  • 1
    Why on earth are you writing `String,Format("{0}", something)`? – SLaks Aug 24 '10 at 16:52
  • Not just that. `something.ToString()`. – recursive Aug 24 '10 at 16:54
  • Year is not the only value I want to get. But I simplified the method. Or is it wrong that I use String.Format at all? It has a much better performance and readability than: x.Year + ":" + x.Month + ":" + ..... – Chris Aug 24 '10 at 16:58
  • Actually, it has much _worse_ performance than `a + b + c` – it's got to parse the format string. It can also be less readable. Also, calling `String.Format("{0}", something)` (without any format string or concatenation is just dumb) – SLaks Aug 24 '10 at 19:54
  • @ SLaks, thank you for your answer. But what is the alternative? Without using the Format string I need to go through boxing (like your seconds posted code). I need to build a complete date/time. In my tests string.Format is MUCH faster. In the other case there is a new string created for every concatenation! – Chris Aug 24 '10 at 21:54
  • 2
    @SLaks the `string,Format("{0}", something)` will work if something is null, while `something.ToString()` will throw null reference exception – achekh Feb 24 '12 at 16:50
  • As an aside you can use `if (val is DateTime)` to replace your condition – gav May 15 '12 at 12:10

3 Answers3

30

Change it to

    return string.Format("{0:yyyy}", val);

To answer the question, the compiler does not realize that T is DateTime.
To perform this cast, you need to cast through object, like this:

    return ((DateTime)(object)val).Year.ToString("0000");
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 6
    Of course, if you cast through object, there are boxing & unboxing step going on. – James Curran Aug 24 '10 at 17:03
  • @James: AFAIK, there is no way to avoid that without making a separate method. – SLaks Aug 24 '10 at 18:18
  • 1
    I agree, but it should be noted. – James Curran Aug 24 '10 at 18:43
  • For others about to walk into the same trap: I started making separate methods and going through all the trouble, before I realized that I was only doing this operation a few times and *the boxing overhead was negligible*. (Despite my itch at technically useless overhead...) – Timo Mar 07 '16 at 12:15
7

I know you said the example was simplified, but consider handling it like this:

private static string GetStringFromValue(DateTime val) 
{ 
    return string.Format("{0}", val.Year.ToString("0000")); 
} 

private static string GetStringFromValue<T>(T val) 
{ 
    return string.Empty; 
} 

The DateTime overload is the best match when an actual DateTime is passed, and the generic version will be used for everthing else. (You could even forgo generic for the second one, and just use an Object)

James Curran
  • 101,701
  • 37
  • 181
  • 258
1

SLaks types faster than I do. :)

But let me add: you might want to re-think your implementation, here, depending on what you're trying to achieve. I assume the reason to have a generic GetStringFromValue method is to emit specific strings from various types. But that's going to end up a bit of a mess once you have, say, a dozen different types in there.

If they're System types, such as DateTime, string.Format() can probably handle all of them, with appropriate format strings. If they're your own types, consider overriding their ToString() methods.

Either way, a little more detail on the problem you're solving would make for interesting answers.

Dan J
  • 16,319
  • 7
  • 50
  • 82