CA1021: Avoid out parameters

TypeName

AvoidOutParameters

CheckId

ca1021

Category

Microsoft.تصميم

تعطيل تغيير

فصل

السبب

أسلوب عام أو محمية في نوع عام يحتوي outمعلمة.

وصف القاعدة

تمرير أنواع مرجع (استخدام outأو ref) يتطلب خبرة مع مؤشرات، فهم كيف بقيمة أنواع و مرجع تختلف أنواع، ومعالجة وظائف مع عدة قيم الإرجاع. وكذلك الفرق بين outو refهو فهم معلمات نطاق واسع.

عند مرجع يتم تمرير نوع "عن طريق مرجع،" الأسلوب يراد بها استخدام معلمة لإرجاع مثيل آخر للكائن. تمرير مرجع اكتب بواسطة مرجع يعرف أيضا باسم استخدام مؤشر مزدوجة، والمؤشر إلى مؤشر أو indirection مزدوج. باستخدام الإعداد الافتراضي اصطلاح، حيث يتم تمرير قيمه"، إحدى معلمات التي تأخذ مرجع نوع مؤشر للكائن تلقي بالفعل. المؤشر، ليس على الكائن الذي يشير، هو التي تم تمريرها حسب قيمة. تمرير بوسيلة القيمة لا يمكن تغيير الأسلوب للحصول على الإشارة إلى مثيل جديد للمؤشر نوع المرجع. ومع ذلك، يمكنك تغيير محتويات الكائن إلى الذي يشير. لمعظم تطبيقات th هو هو كافية وتعطي سلوك الذي تريده.

إذا كان يجب أن يعد أسلوب نسخة مختلفة, باستخدام القيمة الإرجاع للأسلوب إلى القيام بذلك. راجع System.Stringفئة لمجموعة متنوعة من الطرق التي تعمل تشغيل سلاسل و إرجاع مثيل جديد من سلسلة. عند ترتيب هو طراز هو الاستخدام، يجب أن تقرر المتصل ما إذا كان الكائن الأصلي هو المحافظة على.

على الرغم من أن قيم الراجعه كانا commonplace والمستخدمة بكثرة، تطبيق الصحيح من outو refيتطلب معلمات المتوسطة وتصميم ترميز المهارات. مهندسو المكتبة الذي قام بتصميم لجماعة مستهدفة عامة يجب أن لا تتوقع أن المستخدمين إلى الرئيسية باستخدام outأو refمعلمات.

كيف إلى الإصلاح انتهاكات

إلى إصلاح انتهاكا لهذه قاعدة بسبب نوع القيمة، يكون الأسلوب بإرجاع الكائن كالقيمة الإرجاع الخاصة بها. إعادة تصميم إذا كان الأسلوب الذي يجب أن يقوم بإرجاع قيم متعددة، إلى إرجاع مثيل منفرد من أحد الكائنات التي تحتوي على القيم.

إلى إصلاح انتهاكا لهذه قاعدة بسبب نوع مرجع، تأكد من إرجاع مثيل جديد للمرجع هو سلوك الذي تريده. إذا كان ذلك هو، عليك استخدام الأسلوب لالقيمة الإرجاع الخاصة بها للقيام بترتيب هو.

عند إلى منع التحذيرات

هو آمن لمنع ظهور تحذير من القيم بالموضع هو قاعدة. ومع ذلك، قد يؤدي هذا التصميم مشاكل الاستخدام.

مثال

مكتبة التالي بإظهار تطبيقات الثاني من الفئة التي تنشئ استجابات إلى الملاحظات الخاصة بالمستخدم. التنفيذ الأولى ( BadRefAndOut) بإجبار مستخدم مكتبة إلى إدارة ثلاث قيم الإرجاع. التطبيق الثاني ( RedesignedRefAndOut) بتسهيل خبرة مستخدم بإرجاع مثيل clكـs حاوية ( ReplyData) الذي يقوم بإدارة بيانات كـ unit. مفردة

using System;

namespace DesignLibrary
{
   public enum Actions
   {
      Unknown,
      Discard,
      ForwardToManagement,
      ForwardToDeveloper
   }

   public enum TypeOfFeedback
   {
      Complaint, 
      Praise,
      Suggestion,
      Incomprehensible
   }

   public class BadRefAndOut
   {
      // Violates rule: DoNotPassTypesByReference.

      public static bool ReplyInformation (TypeOfFeedback input, 
         out string reply, ref Actions action)
      {
         bool returnReply = false;
         string replyText = "Your feedback has been forwarded " + 
                            "to the product manager.";

         reply = String.Empty;
         switch (input)
         {
            case TypeOfFeedback.Complaint:
            case TypeOfFeedback.Praise :
               action = Actions.ForwardToManagement;
               reply = "Thank you. " + replyText;
               returnReply = true;
               break;
            case TypeOfFeedback.Suggestion:
               action = Actions.ForwardToDeveloper;
               reply = replyText;
               returnReply = true;
               break;
            case TypeOfFeedback.Incomprehensible:
            default:
               action = Actions.Discard;
               returnReply = false;
               break;
         }
         return returnReply;
      }
   }

   // Redesigned version does not use out or ref parameters;
   // instead, it returns this container type.

   public class ReplyData
   {
      string reply;
      Actions action;
      bool returnReply;

      // Constructors.
      public ReplyData()
      {
         this.reply = String.Empty;
         this.action = Actions.Discard;
         this.returnReply = false;
      }

      public ReplyData (Actions action, string reply, bool returnReply)
      {
         this.reply = reply;
         this.action = action;
         this.returnReply = returnReply;
      }

      // Properties.
      public string Reply { get { return reply;}}
      public Actions Action { get { return action;}}

      public override string ToString()
      {
         return String.Format("Reply: {0} Action: {1} return? {2}", 
            reply, action.ToString(), returnReply.ToString());
      }
   }

   public class RedesignedRefAndOut
   {
      public static ReplyData ReplyInformation (TypeOfFeedback input)
      {
         ReplyData answer;
         string replyText = "Your feedback has been forwarded " + 
            "to the product manager.";

         switch (input)
         {
            case TypeOfFeedback.Complaint:
            case TypeOfFeedback.Praise :
               answer = new ReplyData(
                  Actions.ForwardToManagement,
                  "Thank you. " + replyText,
                  true);
               break;
            case TypeOfFeedback.Suggestion:
               answer =  new ReplyData(
                  Actions.ForwardToDeveloper,
                  replyText,
                  true);
               break;
            case TypeOfFeedback.Incomprehensible:
            default:
               answer = new ReplyData();
               break;
         }
         return answer;
      }
   }
}

يوضح تطبيق التالي خبرة مستخدم. المكالمة إلى تمت إعادة تصميمها بالمكتبة ( UseTheSimplifiedClassالأسلوب) هو أكثر مباشرة، والمعلومات التي يتم إرجاعها بواسطة الأسلوب الذي تتم إدارته بسهولة. الإخراج من الاثنين وظائف مماثل.

using System;

namespace DesignLibrary
{
   public class UseComplexMethod
   {
      static void UseTheComplicatedClass()
      {
         // Using the version with the ref and out parameters. 
         // You do not have to initialize an out parameter.

         string[] reply = new string[5];

         // You must initialize a ref parameter.
         Actions[] action = {Actions.Unknown,Actions.Unknown,
                             Actions.Unknown,Actions.Unknown,
                             Actions.Unknown,Actions.Unknown}; 
         bool[] disposition= new bool[5];
         int i = 0;

         foreach(TypeOfFeedback t in Enum.GetValues(typeof(TypeOfFeedback)))
         {
            // The call to the library.
            disposition[i] = BadRefAndOut.ReplyInformation(
               t, out reply[i], ref action[i]);
            Console.WriteLine("Reply: {0} Action: {1}  return? {2} ", 
               reply[i], action[i], disposition[i]);
            i++;
         }
      }

      static void UseTheSimplifiedClass()
      {
         ReplyData[] answer = new ReplyData[5];
         int i = 0;
         foreach(TypeOfFeedback t in Enum.GetValues(typeof(TypeOfFeedback)))
         {
            // The call to the library.
            answer[i] = RedesignedRefAndOut.ReplyInformation(t);
            Console.WriteLine(answer[i++]);
         }
      }

      public  static void Main()
      {
         UseTheComplicatedClass();

         // Print a blank line in output.
         Console.WriteLine("");

         UseTheSimplifiedClass();
      }
   }
}

مكتبة المثال التالي يوضح كيفية refتستخدم المعلمات الخاصة بأنواع مرجع، وتظهر طريقة أفضل إلى تنفيذ هذه الوظائف.

using System;

namespace DesignLibrary
{
   public class ReferenceTypesAndParameters
   {

      // The following syntax will not work. You cannot make a
      // reference type that is passed by value point to a new
      // instance. This needs the ref keyword.

      public static void BadPassTheObject(string argument)
      {
         argument = argument + " ABCDE";
      }

      // The following syntax will work, but is considered bad design.
      // It reassigns the argument to point to a new instance of string.
      // Violates rule DoNotPassTypesByReference.

      public static void PassTheReference(ref string argument)
      {
         argument = argument + " ABCDE";
      }

      // The following syntax will work and is a better design.
      // It returns the altered argument as a new instance of string.

      public static string BetterThanPassTheReference(string argument)
      {
         return argument + " ABCDE";
      }
   }
}

استدعاء تطبيق التالي كل أسلوب في المكتبة لشرح سلوك.

using System;

namespace DesignLibrary
{
   public class Test
   {
      public static void Main()
      {
         string s1 = "12345";
         string s2 = "12345";
         string s3 = "12345";

         Console.WriteLine("Changing pointer - passed by value:");
         Console.WriteLine(s1);
         ReferenceTypesAndParameters.BadPassTheObject (s1);
         Console.WriteLine(s1);

         Console.WriteLine("Changing pointer - passed by reference:");
         Console.WriteLine(s2);
         ReferenceTypesAndParameters.PassTheReference (ref s2);
         Console.WriteLine(s2);

         Console.WriteLine("Passing by return value:");
         s3 = ReferenceTypesAndParameters.BetterThanPassTheReference (s3);
         Console.WriteLine(s3);
      }
   }
}

ينتج هذا المثال الإخراج التالي:

Changing pointer - passed by value: 12345 12345 Changing pointer - passed by reference: 12345 12345 ABCDE Passing by return value: 12345 ABCDE 

جرب الطرق نقش

الوصف

وظائف تنفيذ حاول <Something> نقش، مثل Int32TryParse()، لا إطلاق هذا انتهاك. يظهر المثال التالي بنية (نوع القيمة) الذي يعمل في Int32TryParse()الأسلوب.

الرمز

using System;

namespace Samples
{
    public struct Point
    {
        private readonly int _X;
        private readonly int _Y;

        public Point(int axisX, int axisY)
        {
            _X = axisX;
            _Y = axisY;
        }

        public int X
        {
            get { return _X; }
        }

        public int Y
        {
            get { return _Y; }
        }

        public override int GetHashCode()
        {
            return _X ^ _Y;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Point))
                return false;

            return Equals((Point)obj);
        }

        public bool Equals(Point other)
        {
            if (_X != other._X)
                return false;

            return _Y == other._Y;
        }

        public static bool operator ==(Point point1, Point point2)
        {
            return point1.Equals(point2);
        }

        public static bool operator !=(Point point1, Point point2)
        {
            return !point1.Equals(point2);
        }

        // Does not violate this rule
        public static bool TryParse(string value, out Point result)
        {
            // TryParse Implementation
            result = new Point(0,0);
            return false;
        }
    }
}

القواعد ذات الصلة

لا يجب أن يكون لديك أحداث قبل أو بعد البادئة إدراج علامات في ملف بيانات محلل ملفات التعريف