2

Is it possible at all to check if a type has a parameterless constructor, in order to cast it and call a method which requires a parameterless constructor with the : new() constraint?

Being only able to only check that a type as a public parameterless as answered here would not be enough as it would not allow calling the target methods.

The objective is to have the following logic, where IInteresting objects do not implement a public parameterless constructor and need to be converted before calling Save1:

    public interface IInteresting { }

    public void Save<T>(T o) {
        var oc = o as (new()); /* Pseudo implementation */
        if (oc != null) {
            this.Save1(oc);
        }
        else {
            var oi = o as IInteresting;
            if (oi != null) {
                this.Save2(oi);
            }
        }
    }

    private void Save1<T>(T o) where T : new() {
        //Stuff
    }

    private void Save2<T>(IInteresting o) {
        //Stuff to convert o to a DTO object with a public parameterless constructor, then call Save1(T o)
    }

Of course if I could make Save1 and Save2 share the same signature that would solve the issue, but I cannot find a way to do so as the following will not compile (in Routine, Save will call the first implementation instead of the second):

    public void Routine<T>(T o) {
        var oi = o as IInteresting;
        if (oi != null) {
            this.Save(oi);
        }
    }

    private void Save<T>(T o) where T : new() {
        //Stuff
    }

    private void Save<T>(IInteresting o) {
        //Stuff to convert o to a DTO object with a public parameterless constructor, then call Save(T o)
    }
Community
  • 1
  • 1
Erwin Mayer
  • 18,076
  • 9
  • 88
  • 126
  • 1
    "would not be enough as it would not allow calling the target methods." - actually, it would. [`ConstructorInfo`](http://msdn.microsoft.com/en-us/library/system.reflection.constructorinfo.aspx) has an [`Invoke` method](http://msdn.microsoft.com/en-us/library/6ycw1y17.aspx). – O. R. Mapper Nov 03 '13 at 11:59
  • Just use reflection? But first, rethink your design. – ta.speot.is Nov 03 '13 at 12:01
  • 2
    What is inside your Save1 method? – sh1ng Nov 03 '13 at 12:01
  • The Save method is calling a ServiceStack.OrmLite function which requires an object of a type with a parameterless constructor. I need to convert the object to a DTO (respecting : new()) if it is not one already. – Erwin Mayer Nov 03 '13 at 12:09
  • @O.R.Mapper I don't think ConstructorInfo with its Invoke method would allow me to cast the original object (only create a new one), would it? – Erwin Mayer Nov 03 '13 at 12:14
  • @ErwinMayer: The `ConstructorInfo.Invoke` method allows you to invoke the constructor - which is what I thought you wanted to do, based on your implicit wish of "calling the target methods". Of course, once you have verified that the type in question has a parameterless constructor, you can also use reflection to retrieve the `MethodInfo` of other methods and invoke those. (Though I wonder what bearing the presence or absence of a parameterless constructor could have unless you intend to call it, or have someone else call it.) – O. R. Mapper Nov 03 '13 at 13:33
  • @O.R.Mapper This is a valid approach indeed, which provides a working solution, though I was hoping to avoid Reflection if possible. – Erwin Mayer Nov 03 '13 at 18:06
  • @ErwinMayer All right, I've read the code in the question once more. The use case is quite strange, so I couldn't get it. Thanks for the explanations. – BartoszKP Nov 03 '13 at 18:39

3 Answers3

1

Based on your comments, I imagine you have an object of an unknown type that you want to pass to a generic function that requires the passed-over object to be of the generic type argument, which has to have a parameterless constructor. Hence, for the time being, we can assume that your function Save1<T>(T) from your question is that function, not written by you, not possible to be changed.

A solution to this would be to make the call by using reflection:

O. R. Mapper
  • 20,083
  • 9
  • 69
  • 114
  • Wow that would do it indeed, though I was hoping for a more out of the box way to achieve this. – Erwin Mayer Nov 03 '13 at 17:59
  • 1
    @ErwinMayer: As generics invariably - unless you use reflection - have to be resolved at compile-time, while you know your type only at runtime, I'm afraid there is no viable other way. The only slight simplification you could add to this solution is by using a generic class that itself invokes the generic method based on a non-generic method call - that way, you would skip the `GetMethod` step (which is based on the string-name of the method and thus not compiler-checked) and instead use `typeof(MyCallerType<>).MakeGenericType(o.GetType())`. – O. R. Mapper Nov 03 '13 at 18:20
0

Another possible solution, depending on what you do inside private void Save<T>(T o) where T : new() is to use ICloneable interface. Or introduce yours (as I've said, it depends on Save's contents):

interface IConstructible
{
    object Construct();
}

And have:

private void Save1<T>(T o) where T : ICloneable {

Of course this is just a workaround - O. R. Mapper's answer gives the only direct solution.

Community
  • 1
  • 1
BartoszKP
  • 34,786
  • 15
  • 102
  • 130
0
using System.Reflection;


public static class Generics {
 public static void T0<T> ( T obj ) where T : new () {
  Console.WriteLine ( "{0} {1}", obj, obj.GetType () );
 }

 public static void T1<T> ( T obj ) {
  MethodInfo mi = GenericMethodInfo ( typeof ( Generics ), "T0", typeof ( T ) );
  mi.Invoke ( null, new object[] { obj } );
 }

 public static MethodInfo GenericMethodInfo ( Type classType, string methodName, Type genericType ) {
  return classType.GetMethod ( methodName ).MakeGenericMethod ( genericType );
 }
}


Generics.T0 ( 123 );
Generics.T1 ( 123 );
// Impossible.. Generics.T0 ( "12345" );
Generics.T1 ( "12345" );