С# Передача аргументов по умолчанию - ByRef вместо ByVal
Я знаю, что по умолчанию используется ByVal в С#. Я использовал те же имена переменных во многих местах, а затем заметил, что измененные значения меняются и возвращаются. Я думаю, что я знал, что механизм С# неправильный. Здесь общедоступная лицензия переопределяет значения локальной лицензии. Я знаю, что могу легко переименовать имена переменных в конфликте, но я хотел бы узнать факты о сфере видимости.
public static class LicenseWorks
{
public static void InsertLicense(License license)
{
license.registered = true;
UpdateLicense(license);
}
}
public partial class formMain : Form
{
License license;
private void btnPay_Click(object sender, EventArgs e)
{
license.registered = false;
LicenseWorks.InsertLicense(license);
bool registered = license.registered; //Returns true!
}
}
Обновление: Я добавил ниже как решение:
public static void InsertLicense(License license)
{
license = license.Clone();
...
}
Ответы
Ответ 1
Аргумент передается по значению - но аргумент не является объектом, это ссылка. Эта ссылка передается по значению, но любые изменения, внесенные в объект через эту ссылку, все еще будут отображаться вызывающим.
Это очень отличается от реального прохода по ссылке, где изменяется сам параметр, например:
public static void InsertLicense(ref License license)
{
// Change to the parameter itself, not the object it refers to!
license = null;
}
Теперь, если вы вызываете InsertLicense(ref foo)
, после этого будет foo
null. Без ref, это не так.
Для получения дополнительной информации см. две статьи, которые я написал:
Ответ 2
Вам нужно узнать разницу между ссылочными типами и типами значений. Здесь я предполагаю, что вы используете ссылочную лицензию типа, что означает, что вы фактически разбираете ссылку на соответствующий экземпляр.
Смотрите: http://msdn.microsoft.com/en-us/library/aa711899(v=vs.71).aspx
Хотя, необязательно, правильный тип значения часто выделяется в стеке или в ссылочном типе. Хотя ссылочные типы всегда выделяются на управляемой куче.
Ответ 3
При передаче лицензии в InsertLicense вы передаете ее не по значению, а как ссылку.
Это означает, что при изменении зарегистрированного элемента на true он изменит его, и после возврата ссылки зарегистрированный элемент будет прав.
Ответ 4
Вы передаете аргумент лицензии по значению; по существу это означает, что вы можете изменять любые общедоступные свойства объекта. Однако, если вы переназначаете ссылку объекта лицензии на новый объект, то есть если вы это сделали:
public static void InsertLicense(License license)
{
license = new Licence();
UpdateLicense(license);
}
вызывающий не будет ссылаться на новый объект лицензии, определенный в статическом методе, если вы не передали его по ссылке.
Помните, что все параметры передаются в методы по значению, если вы не используете ключевые слова ref или out.
Ответ 5
Разверните это и подумайте, что я должен поделиться тем, что говорит Microsoft:
"Не путайте концепцию передачи по ссылке с концепцией ссылочных типов. Эти два понятия не являются одинаковыми. Параметр метода может быть изменен посредством ref независимо от того, является ли это типом значения или ссылочным типом. не бокс типа значения, когда он передается по ссылке."
MSDN: ref (ссылка С#)