2013-01-04 1 views
3

저는 오늘 저녁에 사용자 지정 속성을 사용하여 캐싱 계층을 단순화 할 수 있는지 확인했습니다. 이것은 메서드와 클래스에서 사용자 지정 특성을 만들고 사용하는 올바른 방법입니까?

namespace AttributeCreationTest 
{ 
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false)] 
    public class Cache : Attribute 
    { 
     public Cache() 
     { 
      Length = "01h:30m"; 
     } 

     public string Length; 
    } 

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 
    public class CacheIdentifier : Attribute 
    { 
    } 


    [Cache] 
    class Class1 
    { 
     [CacheIdentifier] 
     public int ID { get; set; } 
    } 

    class Class2 
    { 
     [CacheIdentifier] 
     public bool ID { get; set; } 
    } 

    [Cache(Length = "01h:10m")] 
    class Class3 
    { 
     [CacheIdentifier] 
     public string ID { get; set; } 
    } 

    class Program 
    { 

     static void Main(string[] args) 
     { 
      var f1 = new Class1 { ID = 2 }; 
      var f2 = new Class2 { ID = false }; 
      var f3 = new Class3 { ID = "someID" }; 

      DoCache(f1); 
      DoCache(f2); 
      DoCache(f3); 
     } 

     public static void DoCache(object objectToCache) 
     { 
      var t = objectToCache.GetType(); 

      var attr = Attribute.GetCustomAttribute(t, typeof(Cache)); 

      if (attr == null) return; 

      var a = (Cache)attr; 
      TimeSpan span; 

      if (TimeSpan.TryParse(a.Length.Replace("m", "").Replace("h", ""), out span)) 
      { 
       Console.WriteLine("name: {0}, {1}", t.Name, span); 

       ExtractCacheData(objectToCache); 

       return; 
      } 

      throw new Exception(string.Format("The Length value of {0} for the class {1} is invalid.", a.Length, t.Name)); 
     } 

     public static void ExtractCacheData(object o) 
     { 
      var t = o.GetType(); 

      foreach (var prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public)) 
      { 
       if (Attribute.IsDefined(prop, typeof(CacheIdentifier))) 
       { 
        Console.WriteLine(" type: {0}, value {1}", prop.PropertyType, prop.GetValue(o)); 
        break; 
       } 

       throw new Exception(string.Format("A CacheIdentifier attribute has not been defined for {0}.", t.Name)); 
      } 
     } 

    } 
} 

은 "캐시"속성

이 구체화 될 것입니다,하지만 난 C 번호의 영역을 학습하는 동안 최소한의 그것을 떠 났어요 : I는 다음과 같이 올라와있다. 내 아이디어는 개체를 캐싱하는 데 걸리는 시간을 지정하는 단순화 된 방법을 포함하여보다 쉽게 ​​항목을 캐싱 할 수있게하는 것이 었습니다.

이 모양이 좋습니까? 이러한 종류의 패턴을 사용하여 캐시에 항목을 푸는 데 중요한 성능 적중률이 있습니까?

나는 이런 종류의 아이디어를 상세하게 다루는 튜토리얼을 찾을 수 없었으므로 조언을 주시면 감사하겠습니다.

답변

2

귀하의 구현은 괜찮은 것처럼 보이지만, Class1 개체가 아니라 CacheAttribute 개체가 속성 선언 당 하나가됩니다. 즉, 속성을 한 번만 지정하면 Length 속성을 가진 속성의 객체는 clr 중 하나 일뿐입니다.

하지만 객체에서 CacheIdentifier를 검색하기위한 몇 가지 메소드를 정의하는 일부 인터페이스를 DoCache 메소드로 전달하려는 이유는 무엇입니까? 이러한 구현은보다 강력하고 정확하며 읽기 쉽습니다. 확실히 각 클래스에서 구현해야하지만, 책임을 명시하지 않고 objectDoCache에 전달할 때 많은 이점을 얻지 못합니다. 사용자를 위해이 API는 직관적이지 않으며 이해하기 어렵습니다.

또 다른 요점은, 캐싱 목적을 위해 좀 더 발전된 것입니다. 저는 일반적으로 Aspect-Oriented Programming과 PostSharp를 살펴볼 것을 제안합니다. 이 기사 5 Ways That Postsharp Can SOLIDify Your Code: Caching은 캐싱 측면을 구현하는 훌륭한 사례입니다. 간단히, PostSharp 또한 직물의 속성과 IL를 통해 편집의 두 번째 단계에서 동작을 캐시 삽입을 사용

편집 : 당신이 도메인이 아닌 요소의 왜곡없이 좋은 깨끗한 모델을 원하는 경우, 나는로 알려진 또 다른 AOP 기술을, 제안 동적 차단. 가장 널리 사용되는 프레임 워크는 LinFuCastle Dynamic Proxy입니다. 결과적으로 생성자를 통해 종속성을 지정하게되고 이러한 종속성을 해결할 때 IoC 컨테이너가 프록시를 생성합니다. 그러나 요점은 그 모델이 그 프록시에 대해 아무것도 알지 못할 것이고 단순한 객체가있는 곳에서 그것들을 사용할 것입니다. 이것은 다소 유사합니다 Decorator pattern

+0

감사합니다. llya! 이전에 PostSharp를 처음 접한 적이 없지만 확실히 확인할 것입니다. 인터페이스 사용을 고려했지만 DDD를 따르는 프로젝트와 다른 프로그래머가 도메인 이외의 특정 정보를 도메인 객체 (캐시 될 클래스)에 추가하는 데 너무 어려울 지 확신하지 못합니다. 그래도 자랄거야! –

+1

@ChrisW 예. 그러나 속성도 종속성이 있으며 도메인과 관련없는 정보이기도합니다. 그래서 Robert Martin은 Dependency Injection의 속성을'Inject'와 같이 비판했습니다. –

+0

그건 사실이야. 내가 게시 한 직후에 나를 때렸지 만, 내 게시물을 편집하기 전에 대답했다. :). 다른 개발자와 어떤 방법을 사용해야하는지에 대해 이야기 할 것입니다. 어떤 방법을 선택 하든지 관계없이 속성 생성에 대한 배경 지식을 갖는 것이 좋습니다. –

2

사용법은 근본적으로 정확하지만 결과를 캐시 할 수 있습니다. object의 인스턴스를 전달하는 대신 인스턴스에 유형을 전달할 수 있습니다. 또한 매번 Reflection을 사용하지 않아도되도록 - 프로그램 실행을 확실히 가속화하지는 않음 - 사전에 발견 된 유형 및 관련 속성을 사전에 유지하고 메소드가 발견 될 때마다 조회를 수행 할 수 있습니다 조회가 실패한 경우에만 Reflection을 통해 작동합니다.

또한 의무 사항은 아니지만 속성에 대해 naming convention을 따르는 것이 좋습니다.당신의 결과를 유지하는

예 캐시 다음과 같이

static readonly Dictionary<Type, Attribute> CacheAttributes = 
    new Dictionary<Type,Attribute>(); 

은 그럼 당신은 DoCache을 수정합니다 :

var t = objectToCache.GetType(); 
Attribute attr; 
var success = CacheAttributes.TryGetValue(t, out attr); 
if (!success) 
{ 
    attr = Attribute.GetCustomAttribute(t, typeof (CacheAttribute)); 
    CacheAttributes[t] = attr; 
} 
if (attr == null) return; 
var a = attr as CacheAttribute; 
TimeSpan span; 
//Continues with your code 

당신은 ExtractCacheData에 동일한 개념을 적용 할 수 있습니다.