هل من الممكن الاستعلام عن سمات مخصصة في 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 { }

//}

تحرير: فقط لتبرير خياري للإجابة. أعتقد أن كاسبرون شريطة الإجابة الصحيحة من السؤال.

لكن أسباب طلب السؤال بدا ضعيف. وبعد ربما يجب أن أبدأ في استخدام بعض الأداة الخارجية مثل:FinalBuilder.أو إنشاء اختبارات وحدة التحقق لهذا "الشرط"، باستخدام PEX أو NUNIT أو أطر اختبار الوحدة الأخرى ...

تعديلأضفت صغير مقتطف رمز من برنامج وحدة التحكم في نهاية الإجابات التي تنفذ الشيك ... لا تتردد في التعليق أو الانتقاد أو اقتراح التحسينات
مرة أخرى أدركت أن "الشرط" يجب أن تنفذ كجزء من اختبار الوحدة قبل "تسجيل الوصول" فقط

هل كانت مفيدة؟

المحلول

لا، لا يمكن ربطه في تجميع الجمعية والتحقق مما إذا كان موجودا.

ومع ذلك يمكنك ربط في عملية البناء، والتي تتكون من أكثر من مجرد تشغيل المحول البرمجي. يمكنك إنشاء مهمة MSBUILD مخصصة (أو Nant، إذا كنت تستخدم ذلك) والتي تتحقق من التجميع من خلال التفكير بعد أن تم بناؤها ثم تفشل في الإنشاء إذا لم يكن لديك السمات المطلوبة.

بالطبع، ربما يجب عليك ما يزال تحقق من هذا في التعليمات البرمجية كذلك. ما تحاول القيام به ليس بديلا جيدا لفحص وقت التشغيل المناسب.

نصائح أخرى

يمكنك تشغيل خطوة ما بعد البناء التي تعكس DLL للقيام بما تريد.

سيكون عليك كتابة تطبيق سطر الأوامر يقوم بتحميل DLL ويعكس على الأنواع. ثم قم بتشغيل تطبيق سطر الأوامر كخطوة ما بعد البناء. لقد فعلت هذا في الماضي. ليس من الصعب للغاية القيام به، على افتراض أنك تفهم API الانعكاس.

postsharp. هل هذا لتحقيق البرمجة الموجهة نحو الجانب. رائع جدا، في الواقع.

يتم تشغيل السمات وقتا فقط. ومع ذلك :

سيكون من الممكن إنشاء قاعدة في FXCOP (التحليل الثابت) الذي سيفشل في حالة عدم تعريف السمة، وقد تحقق عملية بناء / Checkin الخاصة بك تلك القاعدة وفشلها بشكل مناسب.

أنا لست على دراية بأي طريقة لربط عملية تجميع C #، ولكن قد تتخذ نهجا مختلفا وإنشاء أداة مخصصة تم إطلاقها في حدث ما بعد بناء المنشور الذي يمكن تحميل تجميعك وتعكس ذلك. اعتمادا على عودة الأداة إلى أن عملية الإنشاء بأكملها ستؤدي إلى نجاح أو فشل، لذلك قد تعيد مجرد خطأ في أداةك وجعل "فشل الإنشاء"، مع توفير مزيد من التفاصيل حول فشل الفشل إلى وحدة التحكم.

بالنسبة لي يبدو أن هذا يشبه مشكلة اختبار من مشكلة تجميع. هذا هو، أنت تسأل "كيف أعرف أن رمزي مكتوب بشكل صحيح؟" حيث يحتوي "المكتوبة بشكل صحيح" (من بين أشياء أخرى) الدلالة بأن جميع الفئات مصممة بسمة معينة. وأود أن أفكر في كتابة اختبارات الوحدات التي تحقق من أن قواعد إدراج سمة الخاص بك هي في الواقع. يمكنك إجراء عملية بناء (و / أو Checkin) هذه المجموعة المعينة من الاختبارات بعد الإنشاء (قبل الفحص) كشرط لبناء ناجح (Checkin). لن يكسر الترجمة، حيث يحتاج ذلك إلى إكماله من أجل تشغيل الاختبارات، لكنه سيقتحم المبنى، حتى يتكلم.

//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