-1

I want to refactor the below C# codes:

public static T SomeMethod<T>() where T : SomeBaseClass {}

SomeMethod<Foo>().someProperty = sameValue;
SomeMethod<Bar>().someProperty = sameValue;
SomeMethod<Baz>().someProperty = sameValue;
//...

To like this:

public static T SomeMethod<T>() where T : SomeBaseClass {}

Type[] types = new Type[]{
    typeof(Foo), typeof(Bar), typeof(Baz), //...
};
foreach (Type type in types) {
  // How??
  // SomeMethod<type>().someProperty = sameValue;
}

So I want to prepare the array of types and use foreach to run the same code for more types in future.

crthompson
  • 15,653
  • 6
  • 58
  • 80
Emmettoc
  • 137
  • 2
  • 8

3 Answers3

2

If you do not know at compile time what your types are there is no point using generics.
Refactor your code to change the method signature to something like this:

SomeMethod(Type t){/*do some stuff here*/}

and have a look to the link given by @Florian Gl in the comments.

JB.
  • 40,344
  • 12
  • 79
  • 106
Parv Sharma
  • 12,581
  • 4
  • 48
  • 80
0

If you want to automatically get a list of all types that inherit from a common base type, I would use reflection. It's as simple as:

var assembly = Assembly.GetAssembly(typeof(SomeBaseClass));
var types = assembly.GetTypes().Where(type => typeof(SomeBaseClass).IsAssignableFrom(type));

That said, it looks like you're mucking about with static methods that will set static properties on a bunch of different types. You can use reflection for this, but you would be much better off to take a better approach to this problem that doesn't depend on global state (which is basically what a static property is).

Josh
  • 776
  • 6
  • 20
0

You can invoke a generic method via reflection if you have it's MethodInfo.

First call that MethodInfo's MethodInfo MakeGenericMethod(params Type[] typeArguments) with one type for each generic type argument to the method.

Then call the resulting MethodInfo's object Invoke(object obj, object[] parameters) with the instance of the object you want the method invoked on (or null if it is a static method), and an array of objects containing the arguments to the method in order.

Here is your c# code modified to compile, run, and do something. Example1() is your first code snippet. Example2() does what you want your second code snippet to do.

public class SomeBaseClass {
    public string someProperty {
        set {
            Console.WriteLine(string.Format("someProperty called on {0} with {1}", this, value ) );
        }
    }
}

public class Foo : SomeBaseClass {
}

public class Bar : SomeBaseClass {
}

public class Baz : SomeBaseClass {
}

public static class SomeMethods {
    public static T SomeMethod<T>() where T : SomeBaseClass, new() {
        return new T();
    }
}

class Program
{
    public static void Example1() {
        string someValue = "called from Example1";

        SomeMethods.SomeMethod<Foo>().someProperty = someValue;
        SomeMethods.SomeMethod<Bar>().someProperty = someValue;
        SomeMethods.SomeMethod<Baz>().someProperty = someValue;
    }

    public static void Example2() {
        string someValue = "called from Example2";

        Type[] types = new Type[]{
            typeof(Foo), typeof(Bar), typeof(Baz), //...
        };
        foreach (Type type in types) {
            // Here's how:
            System.Reflection.MethodInfo genericMethodInfo = typeof(SomeMethods).GetMethod("SomeMethod");
            System.Reflection.MethodInfo methodInfoForType = genericMethodInfo.MakeGenericMethod(type);
            var someBase = (SomeBaseClass) methodInfoForType.Invoke(null, new object[] { });
            someBase.someProperty = someValue;
        }
    }

    static void Main(string[] args)
    {
        Console.WriteLine("Example1");
        Example1();

        Console.WriteLine("Example2");
        Example2();

        Console.ReadKey();
    }
}

Here's the output of the program:

Example1
someProperty called on ConsoleApplication1.Foo with called from Example1
someProperty called on ConsoleApplication1.Bar with called from Example1
someProperty called on ConsoleApplication1.Baz with called from Example1
Example2
someProperty called on ConsoleApplication1.Foo with called from Example2
someProperty called on ConsoleApplication1.Bar with called from Example2
someProperty called on ConsoleApplication1.Baz with called from Example2
Cirdec
  • 24,019
  • 2
  • 50
  • 100