7

I try to figure out how I can access a static method within CallMe<T>() of class DoSomething. Is reflection the only solution here? I do not want to instantiate an object of type MyAction. Also if doing it through reflection is there a way to create the method through reflection within the method CallMe<T>() just once and then calling it many times to perform multiple operations on the same "reflected" method? Or is there any better way than through reflection? I basically want to create template implementation style classes such as MyAction that define how byte[] DoThis(string text) performs its duty. The AskForSomething() will then specify which template is being used and according to that the CallMe<T>() will go about its work.

    public class AskSomething
    {
        public void AskForSomething()
        {
            DoSomething doSomething = new DoSomething();
            doSomething.CallMe<MyAction>();
        }
    }

    public class DoSomething
    {
        public void CallMe<T>()
        {
            Type type = typeof(T);

            //Question: How can I access 'DoThis(string text)' here?
            //Most likely by reflection? 
        }
    }

    public class MyAction
    {
        public static byte[] DoThis(string text)
        {
            byte[] ret = new byte[0]; //mock just to denote something is done and out comes a byte array

            return ret;
        }
    }
Matt
  • 7,004
  • 11
  • 71
  • 117

4 Answers4

9

Define an interface with DoThis, have MyAction implement it, and constrain the T type parameter to be an instance of it with where T : IMyInterface

Kieren Johnstone
  • 41,277
  • 16
  • 94
  • 144
  • +1 I was trying to explain why this doesn't work, but it's apparently much simpler just to describe how to make it work... – Rawling Dec 21 '12 at 12:32
  • An interface is the correct way to do this, but if you _must_ have the DoThis as a static method then you will have to use reflection. – Ross Dargan Dec 21 '12 at 12:35
  • @KierenJohnstone, ok so an interface is the way to go it seems. But I assume it would mean I have to pass in an instance of T, correct? – Matt Dec 21 '12 at 14:59
  • @RossDargan, DoThis does not necessarily have to be static. I just want to get around to having to pass in an instance of MyAction class. All I need is access to the DoThis method. – Matt Dec 21 '12 at 15:00
  • I have provided an answer that doesn't require to to pass an instance of T. – Ross Dargan Dec 21 '12 at 15:21
  • ok, how would I access the DoThis method within DoSomething then unless I pass in an instance of T. Sorry I am pretty new to this and T.DoThis("abc") for obvious reasons does not work. – Matt Dec 21 '12 at 15:32
  • 1
    `new T().DoThis("abc")`, or indeed you can pass in an instance. You would need to constrain with `where T : IMyInterface, new()` to ensure it has a parameterless constructor – Kieren Johnstone Dec 21 '12 at 15:44
  • got it great, thanks. Your solution looks to be the most applicable in this specific case. – Matt Dec 21 '12 at 15:52
2

If your DoThis method needs to be static you can also change your CallMe method to the following:

public void CallMe(Func<string, byte[]> action)
{
    byte[] result = action("input");
}

Now you can pass a reference to a function to the CallMe method like this:

 doSomething.CallMe(MyAction.DoThis);
Wouter de Kort
  • 39,090
  • 12
  • 84
  • 103
  • is this similar to a delegate or is a delegate? – Matt Dec 21 '12 at 15:02
  • Yes this a delegate. You can use this delegate to represent a method that can be passed as a parameter without explicitly declaring a custom delegate (see [Func Delegate](http://msdn.microsoft.com/en-us/library/bb549151.aspx)) – Wouter de Kort Dec 21 '12 at 15:12
  • thanks for explaining, would you happen to know by chance what the performance difference is between a delegate and interface implementation? I remember having come across a question similar to this on SO but I can't find it anymore. – Matt Dec 21 '12 at 15:19
  • Here is the stackoverflow question that discussed [interfaces vs delegates](http://stackoverflow.com/questions/2082735/performance-of-calling-delegates-vs-methods) But before worrying about performance this is a nice read: [Which is faster?](http://ericlippert.com/2012/12/17/performance-rant/) – Wouter de Kort Dec 21 '12 at 15:21
  • Thanks thats exactly what I came across before, also thanks for the recommendation to performance profile myself if performance is indeed an issue (here it is, I process about 15-20 million items per second, so even differences in the microsecond realm add up.). – Matt Dec 21 '12 at 15:28
1

Based on the fact that "DoThis" doesn't have to be static you can achieve this with the following:-

using System;

namespace ConsoleApplication3
{
class Program
{
    static void Main(string[] args)
    {
        DoSomething doSomething = new DoSomething();
        doSomething.CallMe<MyAction>();

    }
}
public class DoSomething
{
    public void CallMe<T>() where T : IMyAction
    {
       IMyAction action =  (IMyAction)Activator.CreateInstance(typeof(T));

       var result = action.DoThis("value");            
    }
}

public interface IMyAction
{
    byte[] DoThis(string text);
}

public class MyAction : IMyAction
{
    public byte[] DoThis(string text)
    {
        byte[] ret = new byte[0]; //mock just to denote something is done and out comes a byte array

        return ret;
    }
}
}

Not sure I'd recommend this approach but it works! (for example if there is no default constructor this will fail).

Ross Dargan
  • 5,876
  • 4
  • 40
  • 53
  • Is this a reflection approach? Btw, I think you need to call `doSomething.CallMe()` instead of `doSomething.CallMe()`, correct? – Matt Dec 21 '12 at 15:17
  • yes, the Activator.CreateInstance is effectively reflection. You can use it multiple times if that makes sense (but remember the method CallMe could be called with a different type than the previous call) – Ross Dargan Dec 21 '12 at 15:20
  • of course otherwise I guess the question would be moot if it was not intended to have T be different types that implement IMyAction. Thanks though for pointing out. – Matt Dec 21 '12 at 15:38
0
  public class DoSomething
  {
    class Cache<T>
    {
      public readonly static Func<string, byte[]> action = (Func<string, byte[]>)Delegate.CreateDelegate(typeof(Func<string, byte[]>), typeof(T).GetMethod("DoThis"));
    }
    public void CallMe<T>()
    {
      Cache<T>.action("text");
    }
  }
Serj-Tm
  • 16,581
  • 4
  • 54
  • 61
  • Technically correct, impossibly crap to maintain and design around of course :) – Kieren Johnstone Dec 21 '12 at 13:55
  • @KierenJohnstone We are not looking for an easy way – Serj-Tm Dec 21 '12 at 14:13
  • What? Yes, all software developers should always be looking for an easy way. You can use a pair of scissors to hammer in a nail - someone might even ask, what's the best pair of scissors to hammer in a nail - but of course, every time, you should use a hammer.. – Kieren Johnstone Dec 21 '12 at 14:28
  • @DarkGray, while the interface solution looks more suitable in this case, do you mind explaining how your solution would work in case I decide to use reflection in the future (I am pretty fresh to programming). How would I now call this invoked method within a loop that iterates a million times without having to invoke the method again on each iteration? That was something I think I already brought up in the original question. – Matt Dec 21 '12 at 14:53
  • @DarkGray, to be honest I do not see how your answer avoids having to invoke again and again on each iteration, given the method call is done within a loop. And not sure you are just messin' right before your holidays...it just strikes be as odd you insist on this being a better solution than an interface...anyway thanks! – Matt Dec 21 '12 at 15:55
  • Put it this way - if you think this answer is a good solution to the problem, you're not going to hold down a software job for very long :) – Kieren Johnstone Dec 21 '12 at 15:58
  • Reflection is slow and means "I couldn't think of the correct way to do it", or "I want to do something that I really shouldn't be doing" – Kieren Johnstone Dec 21 '12 at 16:10
  • now you combine delegate and reflection concepts? Sorry but it looks very confusing to me. – Matt Dec 21 '12 at 16:19
  • The performance of this approach will be entirely reasonable if you define a generic static class to hold the delegate that was created for any particular type `T`. Have the class constructor set the delegate to a static method which will attempt to fetch, set, and execute the delegate. If you do that, any exception will occur in the context of using the delegate, rather than in the context of the static constructor, and there will be no need to test whether the delegate has been fetched yet (if it has, it will simply execute directly). – supercat Dec 21 '12 at 16:56
  • @supercat as current variant? – Serj-Tm Dec 21 '12 at 17:34
  • @DarkGray: I'd write it out as multiple lines, and add have the code trap for problems and throw reasonable exceptions rather than `NullReferenceException`, but that's the basic idea. – supercat Dec 21 '12 at 17:57