Aracılığıyla paylaş


CA1021: Out parametrelerinden kaçının

TypeName

AvoidOutParameters

CheckId

CA1021

Kategori

Microsoft.Design

Değişiklik kesiliyor

Bölme

Neden

Ortak türü bir ortak veya korumalı yöntemi olan bir out parametresi.

Kural Tanımı

Türleri başvuruya göre iletmenin (kullanarak out veya ref) nasıl değer türleri ile başvuru türleri farklı anlama ve işleme yöntemleri ile birden fazla dönüş değerleri işaretçilerini deneyim gerektirir.Ayrıca, arasındaki fark out ve ref parametreleri yaygın olarak anlaşılmayan.

Bir başvuru türü "referans" iletildiğinde, farklı bir nesne örneğine geri dönmek için parametre kullanmayı yöntemi tasarladığı.Bir başvuru türü başvuruya göre iletmenin Ayrıca bir çift İşaretçi İşaretçi İşaretçi veya çift başvururken kullanmak adı verilir."Değer" ileten, çağırma varsayılan kullanarak bir başvuru türü zaten götüren bir parametre nesnesi için bir işaretçi alır.Onu gösterdiği, nesne işaretçisi değeri tarafından iletilir.Başvuru tipinin yeni bir örneğine işaret için işaretçiyi yöntemini değiştiremezsiniz değer mi geçer.Ancak, bunu gösterdiği nesnesinin içeriğini değiştirebilirsiniz.Çoğu uygulama için bu yeterli ve istenen davranışı ortaya çıkarır.

Bir yöntem farklı bir örneğini döndürmesi gerekir, bunu gerçekleştirmek için yöntemin dönüş değeri kullanın.Bkz: String sınıfı için çeşitli yöntemler dizelerle çalışmak ve yeni bir örnek, bir dize döndürür.Bu model kullanıldığında, arayan orijinal nesnenin korunup korunmayacağını karar vermeniz gerekir.

Dönüş değerleri commonplace ve yoğun olarak kullanılan, doğru uygulama rağmen out ve ref Ara tasarım ve becerileri kodlama parametreleri gerektirir.Genel İzleyici ile ana çalışma kullanıcılara beklememelisiniz için kimin tasarım kitaplığı mimarları out veya ref parametreleri.

İhlalleri düzeltmek nasıl

Değer türüne göre neden bu kuralı ihlal düzeltmek için nesneyi döndürme değeri olarak geri yöntemi vardır.Yöntem birden çok değer döndürmelidir, değerlerini tutan bir nesneyi tek bir örneği dönmek için yeniden tasarlamanız.

Başvuru türüne göre neden bu kuralı ihlal düzeltmek için istenen davranışı yeni bir başvuru örneği dönmek için olduğundan emin olun.Öyleyse, bunu yapmak için yöntemi dönüş değerini kullanmanız gerekir.

Uyarıları ne zaman

Uyarı Bu kuraldan bastırmak güvenlidir.Ancak, bu tasarım, kullanılabilirlik sorunları neden olabilir.

Örnek

Aşağıdaki kitaplığı görüşler bir kullanıcının oluşturduğu bir sınıfın iki uygulamaları gösterir.İlk uygulama (BadRefAndOut) üç dönüş değerlerini yönetmek için Kütüphane kullanıcı zorlar.İkinci uygulama (RedesignedRefAndOut) bir container sınıfının bir örneği döndürerek kullanıcı deneyimini basitleştirir (ReplyData), verileri tek bir birim olarak yönetir.

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;
      }
   }
}

Aşağıdaki uygulama kullanıcı deneyiminin göstermektedir.Yeniden tasarlanan kitaplığı çağrısına (UseTheSimplifiedClass yöntemi) daha basit olmasına ve yöntemi tarafından döndürülen bilgileri kolayca yönetilebilir.İki yöntem çıktısı aynıdır.

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();
      }
   }
}

Aşağıdaki örnek kitaplığı gösterir nasıl ref parametre baþvuru türleri için kullanılır ve bu işlevi uygulamak için daha iyi bir yolu gösterir.

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";
      }
   }
}

Aşağıdaki uygulama davranışını göstermek için kitaplıktaki her yöntemini çağırır.

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);
      }
   }
}

Bu örnek aşağıdaki çıktıyı üretir.

  

Desen yöntemleri deneyin

Description

Yöntemleri uygulayan <Something> deneyin desen, Int32.TryParse, bu ihlali yükseltmeyin.Aşağıdaki örnek uygulayan bir yapı (değer türü) gösterir Int32.TryParse yöntemi.

Kod

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;
        }
    }
}

İlgili kuralları

CA1045: Türleri başvuruya göre geçirmeyin