Generic method which returns generic type

Z

Zdenko

Hi,

I am curious how to make generic method which will return generic type.
Something like:

class Test {
T Get<T>() {
if(T is int) {
return 1; //return int
}
else if(T is string) {
return "11"; //return string
}
else if(T is DateTime) {
return DateTime.Now; //return DateTime
}
}

void MyTest() {
int i = Get<int>();
string s = Get<string>();
DateTime d = Get<DateTime>();
}
}

Thanks,
Zdenko
 
M

Marc Gravell

You have to always think in terms of T... default(T) would be the most
obvious, which is 0/false for value-types [i.e. blit-zero], and null for
reference-types (and Nullable<T>) -
i.e.

T Get<T>() {
return default(T);
}

Other than that, it gets complicated... many things are possible, but we'd
need a bit more detail on what you want to do. Casting is possible, but
messy, and often involves going to "object" in the middle.

Finally, your method must cover every logical path, even if the catch-all
step is simply throw new NotSupportedException()...

Marc
 
J

Jon Skeet [C# MVP]

Zdenko said:
I am curious how to make generic method which will return generic type.
Something like:

class Test {
T Get<T>() {
if(T is int) {
return 1; //return int
}
else if(T is string) {
return "11"; //return string
}
else if(T is DateTime) {
return DateTime.Now; //return DateTime
}
}

void MyTest() {
int i = Get<int>();
string s = Get<string>();
DateTime d = Get<DateTime>();
}
}

Well, you can get it to work, but it's ugly:

using System;

class Test
{
static T Get<T>()
{
if(typeof(T)==typeof(int))
{
return (T)(object)1; //return int
}
if(typeof(T)==typeof(string))
{
return (T)(object)"11"; //return string
}
if(typeof(T)==typeof(DateTime))
{
return (T)(object)DateTime.Now; //return DateTime
}
return default(T);
}

static void Main()
{
int i = Get<int>();
Console.WriteLine(i);
string s = Get<string>();
Console.WriteLine(s);
DateTime d = Get<DateTime>();
Console.WriteLine(d);
}
}

This is an odd use of generics in the first place though. Could you
give a bit more explanation of why you want to do this? There may be a
better way.
 
R

Rene

Hi Jon,

Interesting, I guess I never really paid any attention to this so I decided
to do a little experiment like the one below:

T Get<T>()
{
return (T)( new Exception() );
}

The example above won't run and gives me a casting compile error.

The interesting thing I see here is that I don't get this error when you try
to cast an *object* to <T> (like in your example).

I find this interesting because the compiler seems to give the code the
benefit of the doubt only when casting from *object* to <T> although the
cast may fail.

However, the compiler will not give the "Exception" object the benefit of
the doubt although it is possible that you could potentially cast the
"Exception" object to "ArgumentException", "InvalidOperationException" or
even "Object" and still be a valid cast.

This looks to me like the compiler has double standards :)
 
M

Marc Gravell

The bahaviour is the same as for non-generic code:

string x = "abc";
int foo = (int)(object)x; // compiles but fails
int bar = (int)x; // doesn't compile
 
J

Jon Skeet [C# MVP]

Rene said:
Interesting, I guess I never really paid any attention to this so I decided
to do a little experiment like the one below:

T Get<T>()
{
return (T)( new Exception() );
}

The example above won't run and gives me a casting compile error.

The interesting thing I see here is that I don't get this error when you try
to cast an *object* to <T> (like in your example).

I find this interesting because the compiler seems to give the code the
benefit of the doubt only when casting from *object* to <T> although the
cast may fail.

However, the compiler will not give the "Exception" object the benefit of
the doubt although it is possible that you could potentially cast the
"Exception" object to "ArgumentException", "InvalidOperationException" or
even "Object" and still be a valid cast.

This looks to me like the compiler has double standards :)

Well, it's following the spec - in this case section 6.2.6 (of the
unified C# 3 spec).

It's allowing a cast from "the effective base class C of T to T". The
effective base class of an unconstrained type parameter (like T in your
case) is object.
 
R

Rene

Well, it's following the spec - in this case section 6.2.6 (of the
unified C# 3 spec).

It's allowing a cast from "the effective base class C of T to T". The
effective base class of an unconstrained type parameter (like T in your
case) is object.

I will never have the brains to tackle the spec document however I continue
to experiment and this compiles:

static T Get<T>() where T : Exception
{
return (T)( (Exception) new object() );
}

So my guess is that "the effective base class" is now the "Exception" class
since the <T> is constrained by "Exception".

Anyway, I am fine with the way things work, I was just wondering what dark
secrets lay underneath the compiler to make decisions such as this one, I
wonder if you would need to cast to object if you where doing this directly
in IL.

Oh well, no biggie :)
 
Z

Zdenko

I would like to parse byte array whic I get from other non .NET application.
Byte array is serialized object. To access specific property I am using:
object o = msg.GetProperty(idx); //where idx is index of property
I would like to make strongly type geters.
I know that property with index 1 is zero and I can write code:
int i = msg.GetInt(1);
Using this approach I would have getters for every type of return value. I
would like to use generic and create single Get method which will handle
parsing of specific field and create proper return value:

int i = msg.Get<int>(3);
string s = msg.get<string>(7);
etc... (for every supported type) or InvalidCastException if field is not of
Generic type T.

Zdenko
 
J

Jon Skeet [C# MVP]

Zdenko said:
I would like to parse byte array whic I get from other non .NET application.
Byte array is serialized object. To access specific property I am using:
object o = msg.GetProperty(idx); //where idx is index of property
I would like to make strongly type geters.
I know that property with index 1 is zero and I can write code:
int i = msg.GetInt(1);
Using this approach I would have getters for every type of return value. I
would like to use generic and create single Get method which will handle
parsing of specific field and create proper return value:

int i = msg.Get<int>(3);
string s = msg.get<string>(7);
etc... (for every supported type) or InvalidCastException if field is not of
Generic type T.

The advantages of the GetInt32, GetDateTime etc approach are:

o It avoids the horrible casting within the method
o It makes it clear which types are supported
o The attempt to use an unsupported type fails to compile time
rather than execution time.
 
Z

Zdenko

o It avoids the horrible casting within the method
o It makes it clear which types are supported
o The attempt to use an unsupported type fails to compile time rather than
execution time.

Every argument is right.
As I said in my first mail: "Out of curiosity".

I do not know how to return value of type T without compiler error.
I would like to know how could I achieve this.

Zdenko
 
J

Jon Skeet [C# MVP]

Zdenko said:
Every argument is right.
As I said in my first mail: "Out of curiosity".

I do not know how to return value of type T without compiler error.
I would like to know how could I achieve this.

See my first post to this thread.
 
Z

Zdenko

I have seen it. I was thinking that someone can come with different
approach.
At least it works.

Thanks
Zdenko
 
A

Anjum Rizwi

protected T ExecuteScalar<T>(DbCommand cmd)
{
object obj;
try
{
obj = db.ExecuteScalar(cmd);
return (T) obj;
}
catch
{
throw;
}
}

It gives me casting error
return (T) obj; //cast error

I call like this
return base.ExecuteScalar<bool>(dbCommand);// It returns 0
 

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