2011-07-26 3 views
17

나는 다음과 같은 컴파일하려고 :.NET 대리자를 정적으로 선언 할 수없는 이유는 무엇입니까?

public static delegate void MoveDelegate (Actor sender, MoveDirection args); 

내가 오류로 나타납니다. "변경 용 '정적'는이 항목에 대한 유효하지 않습니다"

위임자를 호출하는 별도의 클래스를 사용하여 이것을 싱글 톤 내에서 구현하고 있습니다. 문제는 다른 클래스의 싱글 톤 인스턴스를 사용하여 식별자가 아닌 형식에서 대리자를 호출 할 때 비 정적 인 대리자를 선언 할 때도 어떤 이유에서든이를 수행 할 수 없다는 것입니다. 분명히 대리자가 정적 인 경우에만 유형을 통해 직접 참조 할 수 있습니다.

이유가 무엇입니까? MonoDevelop 2.4.2를 사용하고 있습니다.

갱신

다음 코드로 제안 중 하나를 시도 후 : 내가 처리 오류가 발생했습니다

public void Move(MoveDirection moveDir) 
{ 
    ProcessMove(moveDir); 
} 

public void ProcessMove(MoveDirection moveDir) 
{ 
    Teleporter.MoveMethod mm = new Teleporter.MoveMethod(Move); 
    moveDelegate(this, moveDir); 
} 

의 MoveMethod이 형, 그리고이 아니라해야한다는 식별자.

+0

약간의 코드 예제가 문제를 설명하는 데 도움이된다고 생각합니다. 나는 두 번째 단락을 다섯 번 읽었으며 아직도 무엇을 어떻게 성취하고 싶은지 전혀 모른다. –

+0

'ProcessMove' 메쏘드에서'mm' 변수의 목적은 무엇입니까? 만약 어떤 delegate (static 또는 instance)가'moveDelegate'에 할당되면,'moveDelegate'를 호출하면 할당 된 델리게이트가 호출됩니다. – Groo

+0

인터페이스가 더 좋다고 생각합니다. [내 대답]을 참조하십시오 (http://stackoverflow.com/questions/6835766/c-delegate-cannot-be-declared-static/6835948#6835948) –

답변

26

이 시도 :

public delegate void MoveDelegate(object o); 
public static MoveDelegate MoveMethod; 

그래서 방법 - 변수는 정적 정의 할 수 있습니다. static 키워드는 enum 또는 const 정의와 마찬가지로 delegate 정의에는 의미가 없습니다.

정적 메소드 필드 할당하는 방법의 예 :

public class A 
{ 
    public delegate void MoveDelegate(object o); 
    public static MoveDelegate MoveMethod; 
} 

public class B 
{ 
    public static void MoveIt(object o) 
    { 
    // Do something 
    }  
} 

public class C 
{ 
    public void Assign() 
    { 
    A.MoveMethod = B.MoveIt; 
    } 

    public void DoSomething() 
    { 
    if (A.MoveMethod!=null) 
     A.MoveMethod(new object()); 
    } 
} 
+0

나는 꽤 따르지 않는다. 그것이 공공 분야인가, 아니면 방법인가? 필드 인 경우 대리인의 인스턴스를 참조해야합니까? 다른 클래스에서 참조하려고하면 오류가 발생합니다. /. – zeboidlund

+0

예제를 추가했습니다. 보시다시피 static method-variable은 정적 필드처럼 작동합니다. –

+0

"열거 형 또는 const 정의와 똑같은"문구가 정확하지 않습니다. const는 기본적으로 정적 인 특성을 가지므로 const 타입 필드에 대해서는 정적입니다. 주어진 예가 좋다. – Dhananjay

7

delegate 유형을 선언하고 있습니다. static으로 선언하는 것은 의미가 없습니다. 하지만 delegate 유형의 인스턴스를 static으로 선언 할 수 있습니다.

public delegate void BoringDelegate(); 


internal class Bar { 
    public static BoringDelegate NoOp; 
    static Bar() { 
     NoOp =() => { }; 
    } 
} 
+0

"이해할 수 있습니다"실제로 실제로 유용 할 수 있습니다. 인스턴스 메소드를 결코 표현할 수없는'delegate '을 선언 할 수 있습니다. 즉, 관리되는'__thiscall'이 아니라 정적 (static) 또는 인스턴스 클래스 (instance class)의 필수 정적 관리 메소드입니다. 그러한 "델리게이트"타입은'Delegate.Target' 프라퍼티를 갖지 않을 것이고, 그것의 인스턴스는'this' 객체를 저장하기위한 조항을 가지고 있지 않을 것입니다 ... 아마 기존 델리 게이트 타입을위한 기본 클래스입니까? 이점은 IL에서'callvirt' 대신에'call'을 내보내는 것인데, 이는 또한 null 값인'this' 값을 쌓는 것을 피할 수 있습니다. –

0

대리인을 정의하고 정적 클래스에 인스턴스 변수를 선언하십시오.

public delegate void MoveDelegate (Actor sender, MoveDirection args); 

public static MyClass 
{ 
    public static MoveDelegate MoveDelegateInstance; 
} 
2

위임 선언은 실제로 형식 선언이다. 정적 열거 형 또는 구조를 정의 할 수없는 것처럼 정적 일 수 없습니다.

그러나 원시 대리자 대신에 인터페이스를 사용하고 싶습니다. 당신의 호출 코드에서

public interface IGameStrategy { 
    void Move(Actor actor, MoveDirection direction); 
} 

public class ConsoleGameStrategy : IGameStrategy { 
    public void Move(Actor actor, MoveDirection direction) 
    { 
     // basic console implementation 
     Console.WriteLine("{0} moved {1}", actor.Name, direction); 
    } 
} 

public class Actor { 
    private IGameStrategy strategy; // hold a reference to strategy 

    public string Name { get; set; }  

    public Actor(IGameStrategy strategy) 
    { 
     this.strategy = strategy; 
    } 

    public void RunForrestRun() 
    { 
     // whenever I want to move this actor, I may call strategy.Move() method 

     for (int i = 0; i < 10; i++) 
      strategy.Move(this, MoveDirection.Forward); 
    } 
} 

을 :

이 고려 Strategy design pattern에 정신이 유사한

var strategy = new ConsoleGameStrategy(); 

// when creating Actors, specify the strategy you want to use 
var actor = new Actor(strategy) { Name = "Forrest Gump" }; 
actor.RunForrestRun(); // will write to console 

을하고 실제 구현 전략 (콘솔, 그래픽,에서 Actor 움직임을 분리 할 수 ​​있습니다 어떤). 나중에 다른 전략 방법을 사용하여 대리인보다 더 나은 선택을 할 수 있습니다.

마지막으로 Inversion of Control framework을 사용하면 Actor 클래스에 올바른 전략 인스턴스를 자동 주입하여 수동 초기화가 필요하지 않습니다.

+0

저는 텍스트 기반의 게임 엔진을 작성하려고합니다.이 엔진은 객체를 생성하고지도 주위로 움직여 객체 좌표를 콘솔에 표시합니다. 이는 GUI, 그래픽 등을 추가하기 전에 수행해야합니다. 나는 싱글 톤을 만든 텔레포어 클래스를 작성하여 특정 대상으로 객체를 이동시키는 데 사용했습니다. 지금은 간단하게 : MoveDirection.Forward 또는 MoveDirection.Backward. 내가 소식지를 올리 길 원한다면 알려주세요. – zeboidlund

+0

@Holland : 나는 문제가 옳았 으면 인터페이스를 가지고 가고 싶습니다. 내 편집을 참조하십시오. –

5

대리자 선언은 기본적으로 매개 변수 및 반환 형식에 대한 정보 만 포함하는 메서드 서명 을 선언합니다. 동일한 대리자가 정적 메서드와 인스턴스 메서드를 모두 가리킬 수 있기 때문에 메서드 자체를 정적 또는 인스턴스로 만드는 것은 의미가 없습니다. 가이 유형의 대리인이 Actor 매개 변수, 하나 개 MoveDirection 매개 변수를 받아들이는 방법을 가리켜 야한다는 것을 의미

public delegate void MoveDelegate (Actor sender, MoveDirection args); 

와 상관없이, void 반환 : 당신은 귀하의 대리자를 선언하면

메서드가 정적인지 인스턴스인지를 나타냅니다. 네임 스페이스 범위 또는 클래스 내부에서 대리자를 선언 할 수 있습니다 (중첩 클래스를 선언하는 것처럼).

그래서, 당신은 해당 유형의 필드와 변수를 만들 수 있습니다 어딘가에 MoveDelegate를 선언 한 후 :

private MoveDelegate _myMoveDelegate; 

및 방법은 일치 서명이 있어야 기억 : 다음

// parameters and return type must match! 
public void Move(Actor actor, MoveDirection moveDir) 
{ 
    ProcessMove (moveDir); 
} 

public static void MoveStatic(Actor actor, MoveDirection moveDir) 
{ 
    ProcessMove (moveDir); 
} 

을 이 메소드를 다른 장소의 델리게이트에 할당 할 수 있습니다.

private void SomeOtherMethod() 
{ 
    // get a reference to the Move method 
    _myMoveDelegate = Move; 

    // or, alternatively the longer version: 
    // _myMoveDelegate = new MoveDelegate(Move); 

    // works for static methods too 
    _myMoveDelegate = MoveStatic; 

    // and then simply call the Move method indirectly 
    _myMoveDelegate(someActor, someDirection); 
} 

대신 자신의 대표에게 선언의 를 사용할 수있는 미리 정의 된 일반적인 대표 (ActionFunc)를 제공합니다 (버전 V3.5부터) 닷넷 (.NET)를 알고 있으면 유용합니다 :

// you can simply use the Action delegate to declare the 
// method which accepts these same parameters 
private Action<Actor, MoveDirection> _myMoveDelegate; 

위임자를 사용하면 IMHO를보다 쉽게 ​​읽을 수 있습니다. 위임자 자체를 보면서 매개 변수의 서명을 즉시 확인할 수 있기 때문입니다 (사용자의 경우에는 선언을 찾아야합니다.).

+0

대리인의 서명에 대한 귀하의 의견은 괜찮지 만 delegate * instance *가 정적 대 인스턴스 * 메서드 *를 나타내는 지 여부와 관련이 없습니다. 그것은 OP가 도달하고있는 것이 될 수 있습니다 ... 적어도 그것이이 페이지에서 끝난 방법입니다. 아마도 여러분의 대답은 동일한 델리게이트 타입의 두 인스턴스가 표면적으로 같은 서명을 가진 메소드를 나타낼 수 있지만 하나는 정적이고 다른 인스턴스는 메소드를 나타낼 수 있다는 사실을 언급했을 것입니다. C#이 그것을 모호하게하려는 노력에도 불구하고 이해해야 할 중요한 차이입니다. 다른 동기 부여에 대한 다른 의견을 참조하십시오. –

+0

방금 ​​정적 인 대 인스턴스 위임 사이의 (신성하지 않은, IMHO) 관계에 대한 설명을 https://msdn.microsoft.com/en-us/library/z84bd3st(v=vs.110).aspx에서 찾았습니다. 맨 아래에 특히 좋은 코드 예제가 있습니다. –

+0

@Glenn : 아마도 대답을 업데이트해야하지만, .NET에서 대리자는 인스턴스와 정적 메서드를 모두 가리킬 수 있으며 대상에 대한 정보를 내부적으로 저장합니다. 실제로, 이것을 저장할 수있는 몇 가지 다른 방법이 있습니다. "다른 유형의 위임자"(http://mattwarren.org/2017/01/25/How-do-.NET-delegates-work/)에서 [여기] ". 델리게이트의 내부 유형은 JITter가 실제 대상 서명과 일치하도록 매개 변수를 스택에 정렬하는 방법을 결정하는 반면 호출 코드는 매개 변수를 대리자에게 투명하게 전달할 수 있도록합니다. – Groo

-1
public static delegate void MoveDelegate (Actor sender, MoveDirection args); 

내가 당신이 컴파일러는 MoveDelegate 이름이 경우, 클래스를 생성하고 System.MulticastDelegate로를 확장하는 대표

를 선언 할 때 무슨 일이 있었는지 말해 보자.

고정 유형 이외의 고정 유형을 확장 할 수 없으므로

따라서 컴파일러에서 정적 대리인 선언을 허용하지 않는 이유가 여기에 있습니다. 여전히 정적 위임 참조를 가질 수 있습니다.

관련 문제