2009-06-29 4 views
5

는이 전특정 메서드 서명을 따르는 메서드를 적용 할 수있는 방법이 있습니까?

public delegate DataSet AutoCompleteDelegate(
     string filter, long rowOffset); 

내가 그 방법 서명을 적용 할 수있는 다음과 같은 클래스를 만들 수 있다고 가정 해 봅시다? (단 연상 아이디어) :

public class MiddleTier 
{ 
    [Follow(AutoCompleteDelegate)] 
    public DataSet Customer_AutoComplete(string filter, long rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    } 

    [Follow(AutoCompleteDelegate)] 
    public DataSet Item_AutoComplete(string filter, long rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    } 



    // this should give compilation error, doesn't follow method signature 
    [Follow(AutoCompleteDelegate)] 
    public DataSet BranchOffice_AutoComplete(string filter, string rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    }   

} 

[편집]

목적 : 이미 내 middletier의 방법의 속성을 넣어. 인터페이스에 의해 촉진 ((속성 여기에 많은 도움), 다음의 WinForm의 위임 기능에 그들을지도

public abstract class MiddleTier : MarshalByRefObject 
{ 
    // Operation.Save is just an enum 

    [Task("Invoice", Operation.Save)] 
    public Invoice_Save(object pk, DataSet delta); 

    [Task("Receipt", Operation.Save)] 
    public Receipt_Save(object pk, DataSet delta); 


    // compiler cannot flag if someone deviates from team's standard 
    [Task("Receipt", Operation.Save)] 
    public Receipt_Save(object pk, object[] delta); 
} 

다음 런타임에, 내가 모든 middletier의 방법을 반복하고 컬렉션에 놓을 게요 :이 같은 방법을 플러그인 기반 시스템)

속성을 좀 더 자체적으로 만들 수 있다면 컴파일러가 불일치를 잡을 수 있다고 생각합니다. 각 클래스에 메소드를 넣어 만약 내가 생각하고

namespace Craft 
{   
    // public delegate DataSet SaveDelegate(object pk, DataSet delta); // defined in TaskAttribute 

    public abstract class MiddleTier : MarshalByRefObject 
    { 

     [Task("Invoice", SaveDelegate)]   
     public abstract Invoice_Save(object pk, DataSet delta); 

     [Task("Receipt", SaveDelegate)] 
     // it's nice if the compiler can flag an error 
     public abstract Receipt_Save(object pk, object[] delta); 
    } 
} 

, 항상 원격 개체를 인스턴스화 잔인한 것입니다. 별도의 클래스에 배치하면 코드 재사용을 용이하게하는 것이 어려울 수 있습니다. Invoice_Open에 Invoice_Save에 대한 정보가 필요하다고 가정 해 봅시다. 사실 나는 심지어 여기에 (크리스탈) Remoting middletier DataSet에서 호출 된 메서드 내에서 데이터를 가져 와서 다른 메서드에 대한 정보를 가져 와서 자체 DataSet에서 병합하는 보고서를 가지고 있습니다. 모든 middletier에서 발생하고 있으며, 모두 서버 측 (중간 계층)에서 수행됩니다.

+0

어떤 언어입니까? – hlovdal

+0

언어는 C# – Hao

+0

전혀 연습하지 않았기 때문에 대답에 넣지는 않겠지 만, 리플렉션을 통해 (1) 각 메소드에 대해 (2) 클래스의 모든 메소드를 가져올 수 있고 주어진 서명과 속성. –

답변

3

예제에 사용 된 FollowAttributewrite a Static Analysis (say, FxCop) rule을 모두 구현하여 해당 속성으로 태그 된 메서드에 언급 된 대리인과 동일한 서명이 있는지 확인할 수 있습니다. 그래서 가능해야합니다. 클래스를 통해 반영 서명이 속성 선언과 일치하지 않는 경우 실패 쓰기 단위 테스트 :

1

이 언어 기능이 아닙니다,하지만 ...이

이것은 당신이에 대한 검증을 할 수있는 무언가이다.

PostSharp도 컴파일 할 때 흥미로운 옵션을 제공합니다. 나는 당신이 그것을 정확히 어떻게 사용할 지 모르지만 당신이 할 수있는 것으로 의심합니다. ...

11

다른 답변은 분명히 유효하지만 아무 것도 당신의 방법에 [Follow(AutoCompleteDelegate)] 속성을 적용하는 것을 잊어 버리지 않도록 당신을 보호 할 것입니다. 다음

public interface IAutoComplete 
{ 
    DataSet Complete(string filter, long rowOffset); 
} 

public class CustomerAutoComplele : IAutoComplete 
{ 
    public DataSet Complete(string filter, long rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    } 
} 

하고 "자동 completers"을 얻기 위해 factory method pattern을 사용합니다 :

난 당신이 인터페이스를 구현하는 클래스로 방법을 전환하고 더 나을 것이라고 생각

public static class AutoCompleteFactory 
{ 
    public static IAutoComplete CreateFor(string purpose) 
    { 
     // build up and return an IAutoComplete implementation based on purpose. 
    } 
} 

또는

public static class AutoCompleteFactory 
{ 
    public static IAutoComplete CreateFor<T>() 
    { 
     // build up and return an IAutoComplete implementation based on T which 
     // could be Customer, Item, BranchOffice class. 
    } 
} 

일단 인 버텀을 살펴볼 수 있다면 공장 메서드에서 자동 완성 구현 목록을 하드 코딩하는 것을 피하기 위해 제어 및 종속성 주입을 사용합니다.런타임에이를 조회 할 수 있지만 컴파일하는 동안 그들은에서 고려되지 않은

귀하는에 속성으로하는 방법을 제한 할 수없는 -

+0

예제에 두 개의 일치하는 메서드가 있다는 점을 감안할 때 약간의 조정이 필요할 수도 있지만 일반적으로 동의합니다. 심지어 제네릭도 명시 적 인터페이스 구현을 통해 (IAutoComplete 등) 할 수 있습니다. –

+3

어. 팩토리 메소드, 제어 반전 및 종속성 삽입으로 돌아가는 것은 잘못된 경로에 있다는 신호입니다. 각각은 무죄로 보일지도 모르지만 모두 함께 추가하면 지나치게 복잡해질 수 있습니다. 메소드를 "인터페이스를 구현하는 클래스로 바꾸는"것을 중단해야합니다. 이제는 이해하기 쉬운 계획입니다. –

+0

그래, 단순한 자동 완성 기능을 위해 (전체 접근법) 조금 overarchitected 수도 있지만 아름다움은 그것이 모두 점진적이라는 점에 동의한다. 실제로 어느 시점에서라도 멈출 수 있고 여전히 괜찮은 솔루션을 제공 할 수있다. 나는 그것에 대해 더 명백하게 할 수 있었다. –

0

속성은 컴파일시 별도의 메타 정보로 저장됩니다.. 속성의 적용 방법을 제한 할 수 있습니다 (즉, 메소드에서만 또는 둘 이상을 적용 할 수 있는지 여부).

나는 속성이 일치하지 않을 때 경고의 FxCop을 사용하는 것이 좋습니다 것입니다

- 당신이 방법은 이벤트의주의 경우는 지원 유형 캐스트 ​​:

[Follow(AutoCompleteDelegate)] 
public DataSet Customer_AutoComplete(string filter, int rowOffset) 

유효한 위임 될 것이다.

0

일종의.

컴파일 타임에이 동작을 수행 할 수 없습니다. Attributes를 사용하여이 클래스를 간단한 테스트 도구로 밀어 넣거나 포함하는 클래스가 인스턴스화 될 때 즉시 실패하도록 할 수 있습니다.

[AttributeUsage(AttributeTargets.Class)] 
public class EnforceConforms : Attribute 
{ 
    public EnforceConforms(Type myClass) 
     : base() 
    { 
     MethodInfo[] info = myClass.GetMethods(); 

     foreach (MethodInfo method in info) 
     { 
      object[] objs = method.GetCustomAttributes(false); 

      foreach (object o in objs) 
      { 
       Attribute t = (Attribute)o; 

       if (t.GetType() != typeof(ConformsAttribute)) continue; 

       MethodInfo mustConformTo = ((ConformsAttribute)t).ConformTo; 

       ParameterInfo[] info1 = mustConformTo.GetParameters(); 
       ParameterInfo[] info2 = method.GetParameters(); 

       bool doesNotCoform = false; 

       doesNotCoform |= (mustConformTo.ReturnType != method.ReturnType); 
       doesNotCoform |= (info1.Length != info2.Length); 

       if (!doesNotCoform) 
       { 
        for (int i = 0; i < info1.Length; i++) 
        { 
         ParameterInfo p1 = info1[i]; 
         ParameterInfo p2 = info2[i]; 

         if (!p1.ParameterType.Equals(p2.ParameterType)) 
         { 
          doesNotCoform = true; 
          break; 
         } 
        } 
       } 

       if (doesNotCoform) 
       { 
        throw new Exception(myClass.Name + "." + method.Name + " does not conform to required delegate signature"); 
       } 
      } 
     } 
    } 
} 

[AttributeUsage(AttributeTargets.Method)] 
public class ConformsAttribute : Attribute 
{ 
    public MethodInfo ConformTo; 

    public ConformsAttribute(Type type) 
     : base() 
    { 
     if (type.BaseType != typeof(Delegate) && type.BaseType != typeof(System.MulticastDelegate)) throw new Exception("Can only accept delegates"); 

     ConformTo = type.GetMethod("Invoke"); 
    } 
} 

던져 클래스 위에 EnforceConforms (대해서 typeof (myFavoriteClass)), 및 따름 (대해서 typeof (myFavoriteDelegate))에 적절한 방법 위에 다음 (이 :

는 두 가지를 (빨리 해킹) 특성을 고려 해시 파트) typeof (myFavoriteClass) .GetCustomAttributes (false). 정적 초기화 프로그램에서 "정말 빠름"을 실패하거나 테스트 클래스에서 수행 할 수 있습니다 (멋진 결과를 얻으려면 EnforceConforms 특성을 사용하여 어셈블리의 모든 메서드를 찾습니다).

일반적으로이 기능을 사용하지 않아야합니다. 설계에 적절한 대리인 구현을 확인해야하는 경우 가능한 경우 다시 설계해야합니다. 또한 컴파일 시간이 아닌 비트를 사용하면 시간을 많이 절약 할 수 있습니다.

1

왜 이렇게하고 싶은지 물어볼 것입니다. 상속을 통해 클래스를 변경하지 않으려면 클래스를 봉인 된 클래스로 만들 수 있습니다. 앞으로 수업을 변경할 사람이 걱정된다면 2 가지 경우 중 1 가지가 있습니다. 1) 그들은 그들이하는 일을 이해하지 못한다. 악의적 인 프로그래머가 프로그램 텍스트를 편집 할 수있는 권한을 가지고 있다면 악의적 인 일을하지 못하게 할 수있는 방법은 없습니다. 2) 그들은 재사용이 안되는 것으로 현재 이해하지 못하는 방식으로 클래스 기능을 확장합니다.

관련 문제