2017-06-15 70 views
1

我想这样做,但这是不可能的(不能从'void'转换为'System.Action')。发送静态方法+参数作为参数

class Program 
{ 
    public static void Main() 
    { 
     int n = 2; 
     ClassB cb = new ClassB(); 

     cb.SetMethod(ClassA.MethodA(n)); //Cann't convert 'void' to 'System.Action<int>' 

    } 
} 

public class ClassA 
{ 
    public static void MethodA(int a) 
    { 
     //code 
    } 
} 

public class ClassB 
{ 
    Delegate del; 
    public void SetMethod(Action<int> action) 
    { 
     del = new Delegate(action); 
    } 
    public void ButtonClick() 
    { 
     del.Invoke(); 
    } 
} 
public delegate void Delegate(int n); 

我可以发送参数“N”,如在“使用setMethod”方法第二个参数,但我将不得不存储变量到后传递给“del.Invoke(PARAM)”。我想使用“del.Invoke()”。

+0

使用setMethod有一个动作的参数了methodA返回无效参数,所以你必须要改变的返回类型methodA to Action

+0

@StuartLC即使此代码仍然不能工作,“ClassB.ButtonClick”方法正在调用单个参数动作的调用,但不提供参数。这有点不清楚他们想要在这里实现什么......也许他们只是想要一个没有参数的Action:'setMethod((=)=> classA.methodA(n)'你提到了吗? – Clint

+0

请遵循C#的命名规则,这些细节使得你的代码不可读。信 –

回答

2

您似乎对代表有误解。代表代表方法,而不是方法调用。如果您为方法提供参数,则它会成为方法调用。所以在这里:

cb.setMethod(ClassA.methodA(n)); 

ClassA.methodA(n)是一个方法调用,你不能将它分配给委托。

基本上,在这个阶段你不能传递参数。您在调用委托时必须传递参数。例如

del.Invoke(5); 

但是你说你想总是写del.Invoke(),没有参数。那么,那么你不应该使用Action<int>,你应该只使用Action,它不接受任何参数。

class Program 
{ 
    public static void Main() 
    { 
     int n = 2; 
     ClassB cb = new ClassB(); 

     cb.setMethod(() => ClassA.methodA(n)); 

    } 
} 

public class ClassA 
{ 
    public static void methodA(int a) 
    { 
     //code 
    } 
} 

public class ClassB 
{ 
    Delegate del; 
    public void setMethod(Action action) 
    { 
     del = new Delegate(action); 
    } 
    public void ButtonClick() 
    { 
     del.Invoke(); 
    } 
} 
public delegate void Delegate(); 
+0

这很好,也许我对代表有误解,你认为这是一种不好的做法吗?你可以推荐其他方式或类来做类似的事吗? – eag845

+0

@ eag845很难说这是否是不好的做法如果你认为我的答案回答你的问题,请考虑通过点击那个选中标记来接受它! – Sweeper

0

cb.setMethod(new Action(ClassA.methodA));

0

是否要捕捉在调用点整数目前尚不清楚(例如,作为一个闭合),或者你是否有意传递一个参数明确的委托。

这里是前一种情况,当值被捕获:

public static void Main() 
{ 
    var n = 2; 
    var cb = new ClassB(); 
    cb.setMethod(() => ClassA.methodA(n)); 
} 

委托因而不知道捕获的变量,而只是定义为:

public delegate void Delegate(); 

然而,如果你不打算在int调用时传递int,那么int的值需要在ButtonClick中传递:

public static void Main() 
{ 
    var cb = new ClassB(); 
    cb.setMethod(ClassA.methodA); 
} 
public class ClassB 
{ 
    Delegate del; 
    public void setMethod(Action<int> action) 
    { 
     del = new Delegate(action); 
    } 
    public void ButtonClick() 
    { 
     var n = 2; 
     del.Invoke(n); 
    } 
} 
public delegate void Delegate(int n); 

编辑 - 你认为还有更好的办法

没有真正的理由明确要求委托。 ActionFunc(和Action<int>,取决于以上)are already delegates。作为一种改进,您应该在调用之前检查该操作是否已分配。无效条件运算符将将其简化为_action?.Invoke()。但是你可以更进一步,并要求其在构造防止行动从以往未赋值:

public class ClassB 
{ 
    // Can be readonly if it is assigned only ever once, in the ctor. 
    private readonly Action _action; 

    public ClassB(Action action) 
    { 
     Contract.Assert(action != null); 
     _action = action; 
    } 

    public void ButtonClick() 
    { 
     _action(); // i.e. no need for Invoke or null check. 
    } 
} 
+0

'cb.setMethod(()=> ClassA.methodA(n))'Works罚款=)。在你写的最后一个例子中,我想我也不需要委托。但就我而言,你认为还有更好的方法吗? – eag845

+0

是的,它捕获'n'的值,就像设置'setMethod'订阅时一样。我已经添加了一些关于提高'ClassB'安全性的小想法。 – StuartLC