分享
 
 
 

[FxCop.设计规则]6. 避免使用输出参数

王朝other·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

6. 避免使用输出参数原文引用:Avoid out parametersTypeName:

AvoidOutParameters

CheckId:

CA1021

Category:

Microsoft.Design

Message Level:

Warning

Certainty:

50%

Breaking Change:

Breaking

Cause: A public or protected method in a public type has an out parameter.

Rule Description Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods with multiple return values. Also, the difference between out and ref parameters is not widely understood.

When a reference type is passed "by reference," the method intends to use the parameter to return a different instance of the object. (Passing a reference type by reference is also known as using a double pointer, pointer to a pointer, or double indirection.) Using the default calling convention, which is pass "by value," a parameter that takes a reference type already receives a pointer to the object. The pointer (not the object to which it points) is passed by value, meaning that the method cannot change the pointer to have it point to a new instance of the reference type, but can alter the contents of the object to which it points. For most applications this is sufficient and yields the desired behavior.

If a method needs to return a different instance, use the method's return value to accomplish this. See the System.String class for a wide variety of methods that operate on strings and return a new instance of a string. Using this model, it is left to the caller to decide whether the original object is preserved.

While return values are commonplace and heavily used, the correct application of out and ref parameters requires intermediate design and coding skills. Library architects designing for a general audience should not expect users to master working with out or ref parameters.

How to Fix ViolationsTo fix a violation of this rule caused by a value type, have the method return the object as its return value. If the method must return multiple values, redesign it to return a single instance of an object that holds the values.

To fix a violation of this rule caused by a reference type, make sure that returning a new instance of the reference is the desired behavior. If it is, the method should use its return value to do so.

When to Exclude MessagesIt is safe to exclude a message from this rule; however, this design might cause usability issues.

Example CodeExampleThe following library shows two implementations of a class that generates responses to user's feedback. The first implementation (BadRefAndOut) forces the library user to manage three return values. The second implementation (RedesignedRefAndOut) simplifies the user experience by returning an instance of a container class (ReplyData) that manages the data as a single unit.

[C#]

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;

}

}

}

The following application illustrates the user's experience. The call to the redesigned library (UseTheSimplifiedClass method) is more straightforward, and the information returned by the method is easily managed. The output from the two methods is identical.

[C#]

using System;

using DesignLibrary;

namespace TestDesignLibrary

{

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

}

}

}

ExampleThe following example library illustrates how ref parameters for reference types are used, and shows a better way to implement this functionality.

[C#]

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

}

}

}

The following application calls each of the methods in the library to demonstrate the behavior.

[C#]

using System;

using DesignLibrary;

namespace TestDesignLibrary

{

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

}

}

}

This example produces the following output.

Changing pointer - passed by value:

12345

12345

Changing pointer - passed by reference:

12345

12345 ABCDE

Passing by return value:

12345 ABCDE

Related Rules Do not pass types by reference

引起的原因:一个公共类型包含一个含有输出(out)参数的公共或保护型方法

描述:使用引用类型参数,需要了解值类型和引用类型的差别,同时,使用这个方法将会有多个返回值。输出型参数(out)和引用型参数(ref)之间的区别并不被广泛了解。

当一个引用类型被当作引用型参数传递进一个方法,这个方法将使用这个参数返回一个不同的实例对象(将一个引用类型当作引用型参数传递,相当于使用一个双重指针、指向指针的指针或双重间接引用)。使用默认的调用方式(传值调用),方法已经收到一个对象的引用(指针),指针(而不是指向的对象实例)将被作为传值调用送入方法。意味着方法将不能修改这个指针指向一个新的对象实例,但是可以改变指针所指对象的内容。对于大多数应用,这种传值参数已经足够用了。

如果一个方法需要返回不同的对象实例,使用方法的返回值就可以了。类似System.String类,其中的很多方法都都返回一个新的字符串实例,这种模式的好处是,调用方法的人可以决定是否将原始对象丢弃掉。

当一个返回值被经常的使用并且开销很大时,正确的应用out和ref参数需要中级设计和编码能力。适合一般用户的库架构设计应该不期望用户掌握如何工作在out和ref参数。

修复:如果只有一个输出类型的参数,并且是之类型,可以将这个参数作为这个方法的返回值。如果一个方法必须返回多个值,重新设计这个方法返回一个单个的实例代替这些值。

例外:忽略这条规则是安全的。但是这条规则可能会影响可用性。

演示:文中,提供了两个演示程序,第一个演示如何将有多个out类型参数的函数修改为返回单个对象实例的方法。构造一个新的数据结构去存储所有的out类型的参数和函数的返回值。第二个演述了out类型参数,一般类型参数和返回值之间的区别和他们的用法。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有