C#方法的Exchange实现

4

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

因此,我可以在运行时用自己的实现替换现有实现(通过dll等外部来源),或者在其上添加另一个。

我已经搜索过了,但没有找到有价值的信息。


我猜这完全不需要,因为有FuncActiondelegatelambda可以轻松模拟这个。 - Nikson Kanti Paul
@NiksonKantiPaul 这是必要的,当我想要交换一些不属于我的实现时。我会编辑我的问题以便更清楚。 - vrwim
如果要注入您的实现,则应该使用一些IoC / DI模式,否则不需要。 - Nikson Kanti Paul
4个回答

4
您可以使用delegates,让您的代码在运行时指向任何您想要执行的方法。
public delegate void SampleDelegate(string input);

上面是一个函数指针,可以指向任何返回 void,并以 string 为输入的方法。您可以将具有该签名的任何方法分配给它。这也可以在运行时完成。
您还可以在 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) => {//在此处执行所需操作}); 另一种选择是使用策略设计模式。在这种情况下,您声明接口并使用它们来表示提供的行为。
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());

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

我该如何使用它来替换方法实现? - vrwim
@vrwim,你无法直接这样做,因为这是一种不同的方法。但是你可以在一个方法中调用委托。 - Felix K.
@npinti 这不是问题所在,Objective-C中的方法交换是替换运行时将调用的方法实现,因此例如您可以有一个Foo类和bar实现,然后交换该方法,这样每次调用bar时,运行时实际上执行您的方法。这是一项运行时功能,不需要Foo类的创建者做任何事情。 - JustSid
如果可能的话,应该避免使用它,因为它非常不专业,但作为最后一招解决第三方框架中的错误是一个不错的选择。 - JustSid
@npinti 我明白了。我只是想澄清一下原来的问题是什么。我认为传递一个lambda表达式对于OP来说并不可行,因为这在Objective-C中也可以工作,而且方法交换是不鼓励使用的,除非其他所有方法都用尽了(即使如此,人们也应该问自己是否真的应该走这条路)。 - JustSid
显示剩余5条评论

0

虽然在 strongly-typed 语言中,这不是最好的面向对象编程方式,但需要提到的是,自从 .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%的情况下应避免使用这种方法。


谢谢您提供这些信息,但这不是我要找的,我猜这可能是不可能的。 - vrwim
@vrwim 嗯,你想要交换方法啊...顺便说一句,我添加了这个答案是为了引发未来读者的好奇心... - Matías Fidemraizer
@vrwim,你应该重新表述你的问题,不要直接寻求解决方案,而是解释一下你想要实现什么或者你的目标是什么,因为也许你正在尝试用Objective-C的方式在C#中实现某些东西,而在C#中有更好的方法来解决同样的问题。 - Matías Fidemraizer

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);

但是必须建立方法来允许这种运行时替换。


-1
void Test(Action method) {
     if ( method != null ) method.invoke();
}

你可以调用这个

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

修改定义后再次调用

Test( () => { MessageBox.Show("Hi"); } )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接