views:

153

answers:

5

I'm having a problem instantiating an anonymous type in my code.

For some reason, TResponse response = default(TResponse); returns null, even though TResponse has a constructor for it.

Am I being dumb?!

Class:

public class MyClass
{
  public MyResponse GetResponse(MyRequest request)
  {
    return Service<MyRequest, MyResponse>.MakeRequest(
      request,
      delegate() {
        return AnotherService.GetRequest(request);
      }
    );
  }
}

Service class

public static class Service<TRequest, TResponse>
  where TRequest : IRequest
  where TResponse : IResponse
{
  public delegate TResponse UseDelegate();

  public TResponse MakeRequest(TRequest request, UseDelegate codeBlock)
  {
    TResponse response = default(TResponse); // <-- Returns nulll

    response = codeBlock();

    return response;
  }
}
+4  A: 

default(T) does not call type T's default constructor like one might think. default(T) means null for classes, 0 for primitives, and a value with all fields initialized to null or 0 for structs.

see keyword default

Brandon Cuff
+5  A: 

As Brandon has said, default returns null for any reference type.

However, I don't see why you're using it at all - the value you've assigned will be overwritten by the return value of codeBlock() anyway. In other words, you can change your MakeRequest method to just:

public TResponse MakeRequest(TRequest request, UseDelegate codeBlock) { TResponse response = codeBlock();

return response;

}

or even:

public TResponse MakeRequest(TRequest request, UseDelegate codeBlock) { return codeBlock(); }

I'm assuming that in reality there's some more code there... but if you really want to call a parameterless constructor, you can constrain TResponse with:

where TResponse : IResponse, new()

and then use:

TResponse response = new TResponse();

That way you'll get a compile-time guarantee that TResponse has a parameterless constructor; just using Activator.CreateInstance(typeof(TResponse)) without a constraint on TResponse would work, but would delay finding out about the problem where you tried to use response type which didn't have a parameterless constructor.

Furthermore, I don't see any anonymous types in your code - the only way an anonymous type would have a parameterless constructor would be if you used:

new {}

which would be somewhat pointless.

Jon Skeet
Jon, you are right. There is some logic before the codeblock, but essentially, if I don't add the constructor, then I get problems with using unassigned variables.
Dan Atkinson
Jon, thanks for enlightening me. I wasn't aware of the use new().
Dan Atkinson
+1  A: 

For complex types, use the Activator.CreateInstance

So in your example: TResponse response = Activator.CreateInstance<TResponse>();

Jonathon
Or you could just specify the generic type parameter as `where TResponse : IResponse, new()`, and then do `TResponse response = new TResponse();`
LukeH
+1  A: 

you should use new() constraint, and you code will look like this

public static class Service<TRequest, TResponse>
  where TRequest : IRequest
  where TResponse : IResponse, new()
{
  public delegate TResponse UseDelegate();

  public TResponse MakeRequest(TRequest request, UseDelegate codeBlock)
  {
    TResponse response = new TResponse();
    response = codeBlock();

    return response;
  }
}
necrostaz
+1  A: 

If you want to be able to create a new instance of a type parameter you should use the new() generic constrait MSDN.

Mikael Sundberg