3

是否可以在 C# 中交换方法的实现,例如 Objective-C 中的方法调配?

所以我可以在运行时用我自己的(或添加另一个)替换现有的实现(来自外部源,例如通过 dll)。

我已经搜索过这个,但没有发现任何有价值的东西。

4

4 回答 4

4

您可以使用delegates让您的代码指向您希望在运行时执行的任何方法。

public delegate void SampleDelegate(string input);

上面是一个函数指针,指向任何产生void并将 astring作为输入的方法。您可以为其分配具有该签名的任何方法。这也可以在运行时完成。

一个简单的教程也可以在MSDN上找到。

编辑,根据您的评论:

public delegate void SampleDelegate(string input);
...
//Method 1
public void InputStringToDB(string input) 
{
    //Input the string to DB
}
...

//Method 2
public void UploadStringToWeb(string input)
{
    //Upload the string to the web.
}

...
//Delegate caller
public void DoSomething(string param1, string param2, SampleDelegate uploadFunction)
{
    ...
    uploadFunction("some string");
}
...

//Method selection:  (assumes that this is in the same class as Method1 and Method2.
if(inputToDb)
    DoSomething("param1", "param2", this.InputStringToDB);
else
    DoSomething("param1", "param2", this.UploadStringToWeb);

您还可以使用 Lambda 表达式:DoSomething("param1", "param2", (str) => {// what ever you need to do here });

另一种选择是使用Strategy Design Pattern. 在这种情况下,您声明接口并使用它们来表示所提供的行为。

public interface IPrintable
{
    public void Print();
}

public class PrintToConsole : IPrintable
{
    public void Print()
    {
        //Print to console
    }
}

public class PrintToPrinter : IPrintable
{
    public void Print()
    {
        //Print to printer
    }
}


public void DoSomething(IPrintable printer)
{
     ...
     printer.Print();
}

...

if(printToConsole)
    DoSomething(new PrintToConsole());
else
    DoSomething(new PrintToPrinter());

第二种方法比第一种更严格,但我认为这也是实现你想要的另一种方法。

于 2015-12-29T08:12:32.200 回答
0

“替换方法”的唯一方法是使用委托。

如果您的代码如下所示:

public void Foo()
{
    Bar();
}

public void Bar()
{
}

然后,您无法Foo调用除Bar. 您在 Objective-C 中引用的方法调度表在 .NET 中是不可变的。

为了能够指定Foo应该在上面调用哪个方法,您需要使用delegate

public void Foo(Action whichMethod)
{
    whichMethod();
}

你可以这样称呼它:

Foo(Bar);
Foo(Baz);

但是必须构建该方法以允许这种运行时替换。

于 2015-12-29T08:17:53.383 回答
0

虽然这不是在强类型语言中进行面向对象编程的最佳途径,但值得一提的是,自 .NET 4.0 以来,C# 已包含允许动态编程的动态语言运行时 (DLR)。最奇怪的动态对象之一是ExpandoObject:一个完全运行时可扩展的对象:

dynamic expando = new ExpandoObject();
expando.DoStuff = new Func<string>(() => "hello world");

// Now you can swap DoStuff with other method setting another delegate:
expando.DoStuff = new Func<string, string>(text => text + "!");

顺便说一句,正如我上面所说,我在这里分享这种方法只是为了学习目的。它在某些边缘情况下可能很有用,但由于 C# 是一种编译型强类型语言,因此在 99.99% 的情况下您应该避免这种方法。

于 2015-12-29T09:04:10.143 回答
-1
void Test(Action method) {
     if ( method != null ) method.invoke();
}

你可以这样称呼

Test( () => { Console.WriteLine("hello world"); } )

更改def并再次调用

Test( () => { MessageBox.Show("Hi"); } )
于 2015-12-29T08:18:20.847 回答