컴파일 시간 동안 C#의 사용자 정의 속성을 쿼리 할 수 ​​있습니까 (런타임 아님)

StackOverflow https://stackoverflow.com/questions/753255

  •  09-09-2019
  •  | 
  •  

문제

다시 말해서, 각 클래스가없는 경우 ( "필수") 사용자 지정 속성 (예 : 저자 및 버전)이없는 경우 컴파일되지 않는 조립품을 만들 수 있습니까 (확인 코드가 제거되지 않다고 가정)?

다음은 실행 시간 동안 쿼리에 사용한 코드입니다.

using System;
using System.Reflection;
using System.Collections.Generic; 


namespace ForceMetaAttributes
{

    [System.AttributeUsage ( System.AttributeTargets.Method, AllowMultiple = true )]
    class TodoAttribute : System.Attribute
    {
        public TodoAttribute ( string message )
        {
            Message = message;
        }
        public readonly string Message;

    }

    [System.AttributeUsage ( System.AttributeTargets.Class |
        System.AttributeTargets.Struct, AllowMultiple = true )]
    public class AttributeClass : System.Attribute
    {
        public string Description { get; set; }
        public string MusHaveVersion { get; set; }


        public AttributeClass ( string description, string mustHaveVersion ) 
        {
            Description = description; 
            MusHaveVersion = mustHaveVersion ; 
        }

    } //eof class 


    [AttributeClass("AuthorName" , "1.0.0")]
    class ClassToDescribe
    {
        [Todo ( " A todo message " )]
        static void Method ()
        { }
    } //eof class 

    //how to get this one to fail on compile 
    class AnotherClassToDescribe
    { 

    } //eof class 

class QueryApp
{
        public static void Main()
        {

                Type type = typeof(ClassToDescribe);
                AttributeClass objAttributeClass;


                //Querying Class Attributes

                foreach (Attribute attr in type.GetCustomAttributes(true))
                {
                        objAttributeClass = attr as AttributeClass;
                        if (null != objAttributeClass)
                        {
                                Console.WriteLine("Description of AnyClass:\n{0}", 
                                                                    objAttributeClass.Description);
                        }
                }



                //Querying Class-Method Attributes  

                foreach(MethodInfo method in type.GetMethods())
                {
                        foreach (Attribute attr in method.GetCustomAttributes(true))
                        {
                                objAttributeClass = attr as AttributeClass;
                                if (null != objAttributeClass)
                                {
                                        Console.WriteLine("Description of {0}:\n{1}", 
                                                                            method.Name, 
                                                                            objAttributeClass.Description);
                                }
                        }
                }
                //Querying Class-Field (only public) Attributes

                foreach(FieldInfo field in type.GetFields())
                {
                        foreach (Attribute attr in field.GetCustomAttributes(true))
                        {
                                objAttributeClass= attr as AttributeClass;
                                if (null != objAttributeClass)
                                {
                                        Console.WriteLine("Description of {0}:\n{1}",
                                                                            field.Name,objAttributeClass.Description);
                                }
                        }
                }
                Console.WriteLine ( "hit Enter to exit " );
                Console.ReadLine ();
        } //eof Main 
} //eof class 

} //eof namespace 


//uncomment to check whether it works with external namespace 
//namespace TestNamespace {

//  class Class1 { }
//  class Class2 { }

//}

편집 : 답을위한 나의 선택을 정당화하기 위해. Casperone 이이 질문의 정답을 제공했다고 생각합니다.

그러나 질문을하는 이유는 약한. 아마도 다음과 같은 외부 도구를 사용해야 할 것입니다.FinalBuilder또는 PEX, NUNIT 또는 기타 장치 테스트 프레임 워크를 사용 하여이 "요구 사항"을 확인하는 단위 테스트 작성 ...

편집하다나는 작은 것을 추가했다 코드 스 니펫 수표를 수행하는 답변 끝에 콘솔 프로그램의 ...
다시 한 번 나는이 "요구 사항"이 "체크인"직전에 장치 테스트의 일부로 구현되어야한다는 것을 깨달았습니다.

도움이 되었습니까?

해결책

아니요, 어셈블리의 편집에 연결하여 존재하는지 확인할 수 없습니다.

하지만 컴파일러를 실행하는 것 이상으로 구성된 빌드 프로세스에 연결할 수 있습니다. 사용자 정의 MSBuild 작업 (또는 사용중인 경우 NANT)을 만들 수 있으며, 이는 조립품을 구축 한 후 반사를 통해 어셈블리를 확인한 다음 필요한 속성이없는 경우 빌드에 실패 할 수 있습니다.

물론, 아마도 당신은 아마야합니다 아직 코드에서도 확인하십시오. 당신이하려는 것은 적절한 런타임 확인을위한 좋은 대체물이 아닙니다.

다른 팁

DLL을 반영하여 원하는 작업을 수행 할 수있는 사후 단계를 실행할 수 있습니다.

DLL을로드하고 유형을 반영하는 명령 줄 앱을 작성해야합니다. 그런 다음 해당 명령 줄 앱을 구축 후 단계로 실행합니다. 나는 과거에 이것을했다. 반사 API를 이해한다고 가정하면 매우 어렵지 않습니다.

포스트 쇼트 이는 측면 지향 프로그래밍을 달성하기 위해 수행합니다. 실제로 꽤 멋지다.

속성은 시간 만 실행됩니다. 하지만 :

속성이 정의되지 않은 경우 FXCOP (정적 분석)에서 규칙을 작성할 수 있으며 빌드/체크인 프로세스가 해당 규칙을 확인하고 적절하게 실패 할 수 있습니다.

C# 컴파일 프로세스에 연결하는 방법은 알지 못하지만 다른 접근 방식을 취하고 사후 빌드 이벤트에서 시작된 사용자 정의 도구를 만들 수 있으며 조립품을로드하고이를 반영 할 수 있습니다. 도구가 반환하는 내용에 따라 전체 빌드 프로세스를 반환하면 성공 또는 실패가 발생하므로 도구에 오류를 반환하고 빌드에 실패하면 콘솔에 쓰기 실패에 대한 자세한 내용을 제공합니다.

나에게 이것은 컴파일 문제보다 테스트 문제처럼 보인다. 즉, "내 코드가 올바르게 작성되었는지 어떻게 알 수 있습니까?" "올바르게 작성된"곳에는 모든 클래스가 특정 속성으로 장식된다는 의미가 있습니다. 속성 포함 규칙이 실제로 따르는 것을 확인하는 단위 테스트를 작성하는 것을 고려할 것입니다. 빌드 (및/또는 체크인) 프로세스가 빌드 후 (체크인 전) 성공적인 빌드 조건 (체크인)의 조건 으로이 특정 테스트 세트를 실행할 수 있습니다. 테스트가 실행되기 위해 완료해야하기 때문에 컴파일이 깨지지는 않지만 건물을 깨뜨릴 수 있습니다.

//PLEASE COMMENT IF YOU FIND BUGS OR SUGGEST IMPROVEMENTS


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace MustHaveAttributes
{
 [AttributeClass ( "Yordan Georgiev", "1.0.0" )] 
 class Program
 {


 static void Main ( string [] args )
 {
  bool flagFoundCustomAttrOfTypeAttributeClass = false; 
  Console.WriteLine ( " START " );

  // what is in the assembly
  Assembly a = Assembly.Load ( "MustHaveAttributes" );
  Type[] types = a.GetTypes ();
  foreach (Type t in types)
  {
   object[] arrCustomAttributes = t.GetCustomAttributes ( true );


   if (arrCustomAttributes == null || arrCustomAttributes.GetLength ( 0 ) == 0)
   {
    //DO NOT CHECK IN
    ExitProgram ( t, "Found class without CustomAttributes" );
   }


   foreach (object objCustomAttribute in arrCustomAttributes)
   {
    Console.WriteLine ( "CustomAttribute for type  is {0}", t );
    if (objCustomAttribute is AttributeClass)
     flagFoundCustomAttrOfTypeAttributeClass = true; 
   }

   if (flagFoundCustomAttrOfTypeAttributeClass == false)
   { //DO NOT CHECK IN 
    ExitProgram ( t, "Did not found custom attribute of type AttributeClass" );
   }
   Console.WriteLine ( "Type is {0}", t );
  }
  Console.WriteLine ("{0} types found", types.Length );

  //NOW REQUIREMENTS IS PASSED CHECK IN
  Console.WriteLine ( " HIT A KEY TO EXIT " );
  Console.ReadLine ();
  Console.WriteLine ( " END " );
 }



 static void ExitProgram ( Type t, string strExitMsg  )
 {

  Console.WriteLine ( strExitMsg );
  Console.WriteLine ( "Type is {0}", t );
  Console.WriteLine ( " HIT A KEY TO EXIT " );
  Console.ReadLine ();

  System.Environment.Exit ( 1 );

 }
} //eof Program


//This will fail even to compile since the constructor requires two params
//[AttributeClass("OnlyAuthor")]  
//class ClassOne
//{ 

//} //eof class 


////this will not check in since this class does not have required custom
////attribute
//class ClassWithoutAttrbute
//{ }



[AttributeClass("another author name " , "another version")]
class ClassTwo
{ 

} //eof class


[System.AttributeUsage ( System.AttributeTargets.Class |
 System.AttributeTargets.Struct, AllowMultiple = true )]
public class AttributeClass : System.Attribute
{

 public string MustHaveDescription { get; set; }
 public string MusHaveVersion { get; set; }


 public AttributeClass ( string mustHaveDescription, string mustHaveVersion )
 {
  MustHaveDescription = mustHaveDescription;
  MusHaveVersion = mustHaveVersion;
 }

} //eof class 

} // 네임 스페이스

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top