Operator as and generic classes
Asked Answered
O

5

38

I want to make a method:

object Execute()
{
    return type.InvokeMember(..);
}

to accept a generic parameter:

T Execute<T>()
{
    return Execute() as T;

    /* doesn't work:
    The type parameter 'T' cannot be used with the 'as' operator because
    it does not have a class type constraint nor a 'class' constraint */

    // also neither typeof(T), nor T.GetType() are possible

    return (T) Execute(); // ok
}

But I think operator as will be very useful: if result type isn't T method will return null, instead of an exception! Is it possible to do?

Obligato answered 28/3, 2009 at 20:27 Comment(0)
P
76

You need to add

where T : class

to your method declaration, e.g.

T Execute<T>()  where T : class
{

By the way, as a suggestion, that generic wrapper doesn't really add much value. The caller can write:

MyClass c = whatever.Execute() as MyClass;

Or if they want to throw on fail:

MyClass c = (MyClass)whatever.Execute();

The generic wrapper method looks like this:

MyClass c = whatever.Execute<MyClass>();

All three versions have to specify exactly the same three entities, just in different orders, so none are any simpler or any more convenient, and yet the generic version hides what is happening, whereas the "raw" versions each make it clear whether there will be a throw or a null.

(This may be irrelevant to you if your example is simplified from your actual code).

Patrilineage answered 28/3, 2009 at 20:29 Comment(3)
Thanks a lot for you answer. I will use it, check and mark as an answer. And, I have next my code usage: MyClass c = compiler.Execute<MyClass>(); I think it's better then MyClass c = compiler.Execute() as MyClass; (check inside is better then outside, I guess)Obligato
But the check is still needed outside - the check for null! :) By making the user write 'as MyClass', you make it more clear that the check for null is required.Patrilineage
Hm.. It seems that you're right! I will recommend to use 'normal' Execute(), but for end-user it could be helpful to have such 'abnormal' Execute(), in addition 'generic experiment' some way :)Obligato
G
15

You cannot use the as operator with a generic type with no restriction. Since the as operator uses null to represent that it was not of the type, you cannot use it on value types. If you want to use obj as T, T will have to be a reference type.

T Execute<T>() where T : class
{
  return Execute() as T;
}
Gallous answered 28/3, 2009 at 20:31 Comment(0)
H
12

This small piece of code is an exception safe substitution for the as-keyword:

return Execute() is T value ? value : default(T)

It uses the pattern matching feature introduced with C# 7. Use it, if you don't want to restrict the generic parameter to a reference type

Honoria answered 15/10, 2018 at 10:47 Comment(0)
G
1

It seems like you are just adding a wrapper method for casting to the type the user wants, thus only adding overhead to the execution. For the user, writing

int result = Execute<int>();

isn't much different from

int result = (int)Execute();

You can use the out modifier to write the result into a variable in the caller's scope, and return a boolean flag to tell whether it succeeded:

bool Execute<T>(out T result) where T : class
{
    result = Execute() as T;
    return result != null;
}
Gabriellia answered 28/3, 2009 at 20:47 Comment(0)
C
1

Is there a chance that Execute() might return a value type? If so, then you need Earwicker's method for class types, and another generic method for value types. Might look like this:

Nullable<T> ExecuteForValueType<T> where T : struct

The logic inside that method would say

object rawResult = Execute();

Then, you'd have to get the type of rawResult and see if it can be assigned to T:

Nullable<T> finalReturnValue = null;

Type theType = rawResult.GetType();
Type tType = typeof(T);

if(tType.IsAssignableFrom(theType))
{
    finalReturnValue = tType;     
}

return finalReturnValue;

Finally, make your original Execute message figure out which T is has (class or struct type), and call the appropriate implementation.

Note: This is from rough memory. I did this about a year ago and probably don't remember every detail. Still, I hope pointing you in the general direction helps.

Canterbury answered 28/3, 2009 at 20:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.