2010-04-23 1 views
1

동적 인 프록시에 의해 이 () 인터셉트 될 수있는 (정적 또는 인스턴스) 메소드 호출 방법을 고안하려고합니다. C# 확장 메서드로 구현하고 싶지만 정적 메서드에 대한 동적 프록시를 생성하는 방법에 대해 고민하고 있습니다.C#에서 정적 클래스 또는 정적 메서드에 대한 동적 프록시를 생성 할 수 있습니까?

일부 용도는 :

Repository.GetAll<T>().CacheForMinutes(10); 
Repository.GetAll<T>().LogWhenErrorOccurs(); 

//or  
var repo = new Repository(); 
repo.GetAll<T>().CacheForMinutes(10); 
repo.GetAll<T>().LogWhenErrorOccurs(); 

나는 어떤 라이브러리 (linfu 등 castle.dynamic 프록시 2) 개방입니다.

감사합니다.

+2

는하지 마십시오

static public class Repository { //You can wrap the interface (proxy) here if you need... static private readonly IRepository m_Repository = MyDIFactory.Import<IRepository>(); static public IQueryable<T> Query<T>() where T : class { return Repository.m_Repository.Query<T>(); } } 

사용. 그냥 정적 클래스를 피하십시오. 인터페이스로 추상화 된 인스턴스 클래스에 충실하면 더 행복해집니다. 오, 그걸 가로 챌 수 있습니다. –

답변

7

완전히 불가능합니다.

사실 프록시는 모든 인스턴스 메서드에서 생성 될 수 없습니다. 프록시 생성기는 파생 클래스를 만들고 재정의 할 수 있도록 가상이어야합니다.

정적 메서드는 가상이 아니므로 프록시에서 재정의 할 수 없습니다.

(기술적으로이 MarshalByRefObject에서 클래스를 파생하는 가상이 아닌 방법에 대한 해결 방법이지만, 이것에 원격 기반 솔루션은 느리고 투박하고 여전히 정적 메서드를 지원하지 않습니다.)

점을 감안 클래스의 이름이 Repository인데, 대신 이러한 메소드 인스턴스 메소드를 만들 것을 제안 할 것입니다. 이러한 종류의 작업은 일반적으로 시작하려면 static이 아니어야합니다. 숫자가 static이라면 느슨한 결합, 조롱, 의존성 삽입, 단위 테스트 가능성의 특정 양, 방금 발견 한 것처럼 프록 싱과 차단을 많이 잃게됩니다.

+0

@Downvoter :이 이야기를 듣고 싶습니다. 더 좋은 대답이 있니? – Aaronaught

+0

비 가상 메서드에 대한 해결 방법에 대해 좀 더 자세히 설명해 주시겠습니까? 목록 에 Add 메서드를 프록시 처리 할 수 ​​있습니까? – Maslow

+0

@Maslow : 나는 대답 할 수있다. 그러나 나는 너에게 해를 끼치고있다. 'List '는'IList '을 구현하므로 클래스 자체를 절대 프록시해서는 안됩니다. 항상'IList '을 사용하도록 코드를 디자인하고, 자신 만의 구현으로 시작하거나, 동작이 필요할 때'List '을 래핑하십시오. – Aaronaught

0

일반적인 차단 전략은 불가능합니다.

하지만 컴파일 타임에 작동하는 대부분의 AOP 프레임 워크가이를 수행 할 수 있습니다. (예 : PostSharp)

나는 오픈 소스 NConcern AOP Framework에서 일하고 있습니다.

이것은 간단한 .NET AOP 프레임 워크로, 스왑 방식으로 런타임에 가로 채기가 가능합니다.

가상 메서드, 비가 상 메서드 및 정적 메서드에 대해서는 팩토리 패턴 및 상속 요구없이 작업을 수행 할 수 있습니다.

내 추천은 "monkey patch"에 AOP를 사용하는 것을 피하고 정적 메서드는 주류가 아닌 "singleton use shortcut"이어야합니다.

당신의 경우에 shortcup과 DI (Dependency Injection)와 같은 정적 메소드를 사용하는 싱글 톤 패턴을 사용하여보다 쉬운 프록시 패턴을 사용하는 것이 더 쉽습니다.

예 :

public interface IRepository 
{ 
    IQueryable<T> Query<T>() 
     where T : class; 
} 

DI를 사용하여 설탕 (공장을 통해)

인터페이스

Repository.Query<T>().CacheForMinutes(10); 
Repository.Query<T>().LogWhenErrorOccurs(); 
관련 문제