3

Here's an example of what I want to accomplish:

abstract class DoSomething
{
    static void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You asked the abstract class to work. Too bad.");
    }
}

class InspireMe : DoSomething
{
    static void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You are amazing.");
    }
}

class InsultMe : DoSomething
{
    static void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You aren't worth it.");
    }
}

class Program
{
    static void Main()
    {
        DoSomething worker = InsultMe;
        worker.DoWhateverItIsThatIDo(); 

        worker = InspireMe;
        worker.DoWhateverItIsThatIDo();
    }
}

I'm coming from a Python background where a method itself can be a variable, which can then be called. It looks like C# doesn't have this concept, but I'm trying to accomplish something similar.

The idea is I want a variable that can be of an abstract type, so that many different kinds of subtypes could exist within it. All of these subtypes would have a certain method. I want to be able to assign any of those subtypes to this variable of the abstract type and then call the static methods that exist in the subtypes.

In C# terminology, I want to be able to assign the class to a variable, not an instance of the class, and then call that class's static methods.

A factory sounds like it might be on the right path, but I'm not sure how the factory itself would be able to generate these references to the class (rather than creating instances).

I could rework this to use instances, but suppose I wanted to have static methods that generate classes of each type, all of which still inherit from the base type.

I feel like there is most likely a way to do this - could someone advise please?

fdmillion
  • 4,823
  • 7
  • 45
  • 82
  • A method can be a variable, in a sense: http://stackoverflow.com/questions/6695537/is-there-a-way-to-save-a-method-in-a-variable-then-call-it-later-what-if-my-met – neminem Jan 21 '15 at 21:52
  • How about `Action workerMethod = InspireMe.DoWhateverItIsThatIDo; workerMethod();`? Not exactly what you wrote, but if you want an actual `worker` object on which you can call multiple methods then you shouldn't use static methods. – Pieter Witvoet Jan 21 '15 at 21:58

5 Answers5

4

You can't use a class as a variable in C# in the sense that you are describing. Reflection would essentially allow you to treat types as variables and dynamically call static members on them, but it would be messy and not typesafe.

You can essentially accomplish what you are trying to do by using the singleton pattern:

interface IDoSomething
{
    void DoWhateverItIsThatIDo();
}

class DoSomething : IDoSomething
{
    private DoSomething() {}
    internal static readonly IDoSomething Instance;
    static DoSomething()
    {
        Instance = new DoSomething();
    }

    public void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You asked the abstract class to work. Too bad.");
    }
}

class InspireMe : IDoSomething
{
    private InspireMe() {}
    internal static readonly IDoSomething Instance;
    static InspireMe()
    {
        Instance = new InspireMe();
    }

    public void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You are amazing.");
    }
}

class InsultMe : IDoSomething
{
    private InsultMe() {}
    internal static readonly IDoSomething Instance;
    static InsultMe()
    {
        Instance = new InsultMe();
    }

    public void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You aren't worth it.");
    }
}
class Program
{
    static void Main()
    {
        IDoSomething worker = InsultMe.Instance;
        worker.DoWhateverItIsThatIDo(); 

        worker = InspireMe.Instance;
        worker.DoWhateverItIsThatIDo();
    }
}
JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • 3
    As it is, the code won't compile; your derived types don't have a constructor of the base type to call (the only one is private), and so won't compile. And if you did expose a constructor to them then the types wouldn't be singletons, what with you creating multiple instances of the types and all. – Servy Jan 21 '15 at 21:59
  • @Servy I don't see any derived classes in the example, just interface implementations so no compilation issues. – John Bowen Jan 21 '15 at 22:06
  • @Servy Sorry you had to critique my half-baked code. I have now verified that it compiles and works as expected. – JLRishe Jan 21 '15 at 22:07
  • I don't think there is any reason for a singleton or the static code at all. static code is bad to produce anyway. impossible to test without resorting to injection. He doesn't seem to understand c# IMO... Because all that is necessary is the interface and at most a single abstract class with a virtual method. – phillip Jan 21 '15 at 22:14
  • @phillip It seems OP wants a number of static objects that fit a certain interface. Isn't that a good use case for the singleton pattern? The `static` parts of the code aren't really doing much. Just calling an empty constructor and assigning it to a field. – JLRishe Jan 21 '15 at 23:01
2

A work-around might be to declare a property of type Action in the base abstract class, that holds the method to be called. Then initialize this property during derived classes instantiation, by calling base class constructor:

abstract class DoSomething
{
    public Action DoWhateverItIsThatIDo { get; set; }

    protected DoSomething() { DoWhateverItIsThatIDo = DoSomething.DoIt; }

    protected DoSomething(Action whatAction)
    {
        DoWhateverItIsThatIDo = whatAction;
    }

    protected static void DoIt()
    {
        Console.WriteLine("You asked the abstract class to work. Too bad.");
    }
}

class InspireMe : DoSomething
{
    public InspireMe() : base(InspireMe.DoIt) { }

    private static void DoIt()
    {
        Console.WriteLine("You are amazing.");
    }
}

class InsultMe : DoSomething
{
    public InsultMe() : base(InsultMe.DoIt) { }

    private static void DoIt()
    {
        Console.WriteLine("You aren't worth it.");
    }
}

class DoWhatBaseClassDoes : DoSomething
{
    public DoWhatBaseClassDoes() : base() {}
}

class Program
{
    static void Main(string[] args)
    {
        DoSomething worker = new InsultMe();
        worker.DoWhateverItIsThatIDo();

        worker = new InspireMe();
        worker.DoWhateverItIsThatIDo();

        // In this case base class method is invoked
        worker = new DoWhatBaseClassDoes();
        worker.DoWhateverItIsThatIDo();
    }
} 
Giorgos Betsos
  • 71,379
  • 9
  • 63
  • 98
1

Classes and instances aside, what you really want to have is a reference to a method with a specific signature, in your case void ().

While you cannot assign a static class to a variable, you can assign a method to a variable in a type-safe manner. In C# you'd usually use an overload of Action or Func, depending on how the method signature should look like.

To make this a bit more interesting, let's assume you want to refer to something like int Foo(string, bool), just use a variable of type Func<string,bool,int> and assign any method that has this signature to it.

The code to solve your problem could roughly look like this:

class DoSomething
{
    static void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You asked the abstract class to work. Too bad.");
    }
}

class InspireMe
{
    static void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You are amazing.");
    }
}

class InsultMe
{
    static void DoWhateverItIsThatIDo()
    {
        Console.WriteLine("You aren't worth it.");
    }
}

class Program
{
    static void Main()
    {
        Action worker = InsultMe.DoWhateverItIsThatIDo;
        worker(); 

        worker = InspireMe.DoWhateverItIsThatIDo;
        worker();
    }
}
Florian Greinacher
  • 14,478
  • 1
  • 35
  • 53
  • You get my vote but question is... I thought he wanted DoSomething.DoWhateverItIsThatIDo() to be the default method that gets called if it didn't exist within InspireMe or InsultMe... Maybe I'm wrong - We shall see. – phillip Jan 21 '15 at 22:22
  • Doesn't compile - `InsultMe` and `InspireMe` are types, not `Action`s - that should be `Action worker = InsultMe.DoWhateverItIsThatIDo;` and then `worker();`. You may want to add a `public` modifier to those static methods too. ;) – Pieter Witvoet Jan 21 '15 at 22:24
  • Thanks Pieter, fixed it – Florian Greinacher Jan 21 '15 at 22:32
0

Neither C# not Java can let you override static base class methods.

However, you appear to be using a reference to an object anyway (your worker variable), so why not just use a non-static class method?

(If this is not what you meant to be doing, please clarify.)

David R Tribble
  • 11,918
  • 5
  • 42
  • 52
0

I'm not 100% sure this is what you want, but I wrote a library that simulates Prototypal inheritance in C#.

public class Foo: ProtoObject {}
public class Bar: Foo {}

dynamic myFoo = new Foo();
dynamic yourFoo = new Foo();
dynamic myBar = new Bar();

myFoo.Prototype.Name = "Josh";
myFoo.Prototype.SayHello = new Action(s => Console.WriteLine("Hello, " + s));

yourFoo.SayHello(myBar.Name); // 'Hello, Josh'

This of course involves heavy use of the dynamic keyword, which may not be useful because you lose a lot of compile time checking.

Josh
  • 44,706
  • 7
  • 102
  • 124