最近有人问我,在一个方法中是否可以有一个仅限输入的参数?我对这个问题的直接回答是“不”,但当我再次思考时,我不确定我是否分享了正确的信息。另外,我没有一个合理的解释来解释为什么.NET不允许我们有一个仅输入的参数,就像我们在实现Contravariance时使用的那样。
发布于 2013-10-18 03:13:13
你可以在这里读到关于Passing Parameters的内容。
我认为当你说“仅限输入”时,你指的是通过值传递的参数。
在c#中,通常按值传递参数。当你传递一个对象时,你是在通过值传递一个“指针”。所以如果你改变了指针所指向的位置,外部的变量也不会改变。但是如果你改变了对象的东西,因为两个“指针”都指向同一个对象,所以它们都会看到变化。
因此,您可以通过"value“传递所有内容,但如果您正在传递对象,则必须创建它的副本,以避免它被您正在调用的方法修改。
你可以在这里看到一个小的测试例子来理解我的意思。
[TestMethod]
public void TestMethod()
{
var john = new Person() { Name = "John" };
var tom = new Person() { Name = "Tom" };
var person1 = john;
var person2 = tom;
SwapPersonsMethod1(person1, person2);
//Person1 is still John
Assert.AreEqual(person1, john);
//Person2 is still Tom
Assert.AreEqual(person2, tom);
SwapPersonsMethod2(ref person1, ref person2);
//Person1 is still Tom
Assert.AreEqual(person1, tom);
//Person2 is still John
Assert.AreEqual(person2, john);
UpdateName(person1, "Tomas");
//Person1 is pointing to var tom, and its name now is Tomas.
Assert.AreEqual(person1.Name, "Tomas");
Assert.AreEqual(tom.Name, "Tomas");
SwapPersonsMethod3(person1, person2, "Jonathan");
//Person1 is still Tom
Assert.AreEqual(person1, tom);
//Person2 is still John
Assert.AreEqual(person2, john);
//John name has changed to Jonathan
Assert.AreEqual(person2.Name, "Jonathan");
Assert.AreEqual(john.Name, "Jonathan");
}
private void UpdateName(Person person, string name)
{
person.Name = name;
}
private void SwapPersonsMethod1(Person person1, Person person2)
{
var aux = person1;
person1 = person2;
person2 = aux;
}
private void SwapPersonsMethod2(ref Person person1, ref Person person2)
{
var aux = person1;
person1 = person2;
person2 = aux;
}
private void SwapPersonsMethod3(Person person1, Person person2, string name)
{
var aux = person1;
person1 = person2;
person2 = aux;
UpdateName(person1, name);
}
public class Person
{
public string Name { get; set; }
}发布于 2013-10-18 03:45:29
我在这里进行了一次大胆的尝试,但听起来您似乎是在问是否可以防止被调用函数更改参数的内容(如调用者所见)。
public void Run()
{
Person Bob = New Person();
Bob.LikesToProgram = false;
Helper(Bob);
Console.WriteLine("Bob likes to program = " + Bob.LikesToProgram);
//Output: Turns out Bob likes to program!!!
}
public void Helper(Person input)
{
input.LikesToProgram = true;
} 你的问题的答案是。。。这取决于参数类型!
和
您始终可以通过模式创建不可变类型!
通过值传递的
所有参数都是“按值”的。有趣的是,如果参数不是一个值,而是指向该值(尽管引用会更准确)。
这就把我们带到。。。
对象
我们在那里做的是Passing a reference to an 。
(正如@Servy所指出的,“通过值传递引用”。)
如果我们传递了一个原语(不是引用类型),Helper中的更改将停留在helper中。。。
原语
要使原语的行为类似于引用类型(这将与您所要求的完全相反),您需要使用ref keyword。
"Object“异常
某些语言允许您通过显式定义 immutable对象。也就是说,有直接的编译器支持来实现不可变性。请参阅链接的文章以获取示例。
换句话说,如果我创建了一个Person并将实例传递给一个新方法,那么该方法就会生效。接收自己的person副本!
string继承自Object,但当您更改String时,会创建一个新的string实例。
需要明确的是,通过模式还有其他不可变的对象,但直接支持意味着您永远不需要编写
public void Run()
{
String foo = "foo";
Helper(foo);
}
public void Helper(String input)
{
input = new String(Foo + "Bar");
//Or CopyTo as seen in Arrays, etc.
}总会有办法的!
如果您使用此策略,则如果对象实现iCloneable将非常有用。为什么要问iCloneable?Deep Copy Vs Shallow
希望这能有所帮助!
更新: @Dzyann首先提供了一个类似的答案(我太冗长了,活该)。如果你喜欢我的回答,也一定要给他打个勾。
发布于 2013-10-18 03:17:14
我认为,您应该停止在c#中使用不同的名称。您可以在MSDN上阅读有关ref和out关键字的内容。我只想让你知道原始类型
void MyVoid(int p1)通过值传递-表示它们被复制。在这里我必须纠正一下:其他类型也传递了byVal,但是作为对现有对象的引用。
如果通过引用传递所有参数,您的代码将更快,但更危险,因为这样可以节省时间,因为不复制它。但是,在这种情况下,您将需要具有较高的编码规则。
“我没有一个合理的解释来解释为什么.NET不允许我们有一个只有输入的参数”--这正是.Net对传递给byval的原始类型有效的解释。
想象一下,如果.net不得不复制所有作为参数传递的对象结构,它的效率会有多低?我猜,这就是为什么MS决定将对象类型作为引用传递
https://stackoverflow.com/questions/19435032
复制相似问题