C# Pass a Class as a parameter

2019-07-15 12:40发布

问题:

I have an Interface, that has some methods

interface IFunction
{
    public double y(double x);

    public double yDerivative(double x);
}

and I've got static classes, that are implementing it.

static class TemplateFunction:IFunction
{
    public static double y(double x)
    {
        return 0;
    }

    public static double yDerivative(double x)
    {
        return 0;
    }
}

I want to pass this classes as a parameter to another function.

 AnotherClass.callSomeFunction(TemplateFunction);

And some other class that catches the request

class AnotherClass
{
    IFunction function;
    public void callSomeFunction(IFunction function)
    {
        this.fuction = function;
    }
}

Well, it doesn't work... I've tried to use the Type expression, but that seams to break the idea of using an interface. Does anyone have an idea, how to correct the code?

回答1:

Static classes can't implement interfaces, but you can easily overcome this by making your class non static and a generic method:

class AnotherClass
{
    IFunction function;

    public void callSomeFunction<T>()
        where T: IFunction, new()
    {
        this.fuction = new T();
    }
}

This is much close to the syntax you wanted:

AnotherClass.callSomeFunction<TemplateFunction>();

But I actually think that this way is too complicated and likely to confuse someone, you should follow Servy's approach which is way simpler:

AnotherClass.callSomeFunction(TemplateFunction.Instance);


回答2:

The conceptual way of getting a static class to implement an interface is to use a singleton, even if that singleton contains no state:

public sealed class TemplateFunction : IFunction
{
    private TemplateFunction() { }
    private static TemplateFunction instance = new TemplateFunction();

    public static TemplateFunction Instance { get { return instance; } }

    public double y(double x)
    {
        return 0;
    }

    public double yDerivative(double x)
    {
        return 0;
    }
}

Another option is to just not use an interface, and instead have your method accept one or more delegates. It's fine if you only need a single method, if you have two it can sometimes be okay, and sometimes not. If you have more than two, it's usually a problem.

public class AnotherClass
{
    public static void callSomeFunction(Func<double, double> y
        , Func<double, double> yDerivitive)
    {
        //store delegates for later use
    }
}

AnotherClass.callSomeFunction(TemplateFunction.y, TemplateFunction.yDerivative);


回答3:

How about you use a generic method to catch the type that you are calling for.

Like this:

public void callSomeFunction<T>()
{
    //the type is T
    //you can create an instance of T with System.Activator.CreateInstance(T) and T's methods
    //alternatively if the classes are static you can call the methods with reflection knowing only their name.
}

And anyway, if the reason you want to do this is because you want to have multiple classes that implement the same methods and you want to write a method that will call a certain implementation of those methods based on type, then other solutions might be in order, like overloading.

Or if indeed this is what you want to do, then keep in mind that passing an interface won't allow you to use the approach i presented you with, because the Activator needs to have access to the Type so that it can create an instance.



回答4:

You can do as Allon said and change the TemplateFunction to none static and then do this:

var anotherClass = new AnotherClass();
var templateFunction = new TemplateFunction();

anotherClass.callSomeFunction(templateFunction);