Что означают ref, val и out для параметров метода?
Вопрос
Я ищу ясный, краткий и точный ответ.
В идеале в качестве фактического ответа, хотя ссылки на хорошие объяснения приветствуются.
Это касается и VB.Net, но ключевые слова другие — ByRef
и ByVal
.
Решение
По умолчанию (в C#) передача объекта функции фактически передает копию ссылки на этот объект.Изменение самого параметра меняет только значение параметра, а не указанную переменную.
void Test1(string param)
{
param = "new value";
}
string s1 = "initial value";
Test1(s1);
// s1 == "initial value"
С использованием out
или ref
передает ссылку на переменную, указанную при вызове функции.Любые изменения стоимости out
или ref
параметр будет передан обратно вызывающей стороне.
Оба out
и ref
ведут себя одинаково, за исключением одного небольшого различия: ref
параметры должны быть инициализированы перед вызовом, в то время как out
параметры могут быть неинициализированы.По расширению, ref
параметры гарантированно инициализируются в начале метода, а out
параметры рассматриваются как неинициализированные.
void Test2(ref string param)
{
param = "new value";
}
void Test3(out string param)
{
// Use of param here will not compile
param = "another value";
}
string s2 = "initial value";
string s3;
Test2(ref s2);
// s2 == "new value"
// Test2(ref s3); // Passing ref s3 will not compile
Test3(out s2);
// s2 == "another value"
Test3(out s3);
// s3 == "another value"
Редактировать:Как дп указывает на разницу между out
и ref
применяется только компилятором C#, а не CLR.Насколько я знаю, у VB нет эквивалента для out
и реализует ref
(как ByRef
) только, что соответствует поддержке CLR.
Другие советы
Еще одно замечание по поводу ref vs.вне:Различие между ними обеспечивается компилятором C#.CLR не делает различия между out и ref.Это означает, что у вас не может быть двух методов, сигнатуры которых отличаются только out или ref.
void foo(int value) {}
// Only one of the following would be allowed
// valid to overload with ref
void foo(ref int value) {}
// OR with out
void foo(out int value) {}
out
означает, что параметр будет инициализирован методом:
int result; //not initialised
if( int.TryParse( "123", out result ) )
//result is now 123
else
//if TryParse failed result has still be
// initialised to its default value (0)
ref
заставит передать базовую ссылку:
void ChangeMyClass1( MyClass input ) {
input.MyProperty = "changed by 1";
input = null;
//can't see input anymore ...
// I've only nulled my local scope's reference
}
void ChangeMyClass2( ref MyClass input ) {
input.MyProperty = "changed by 2";
input = null;
//the passed reference is now null too.
}
MyClass tester = new MyClass { MyProperty = "initial value" };
ChangeMyClass1( tester );
// now tester.MyProperty is "changed by 1"
ChangeMyClass2( ref tester );
// now tester is null
Один из моих вопросов в stackoverflow также касается этой темы.
Он обрабатывает около «передавать по ссылке» и «передавать по значению» на разных типах языков, С# включен так что, возможно, вы также сможете найти там дополнительную информацию.
В основном это сводится к:
- ссылка:будет передан параметр с ключевым словом ref по ссылке
- вне:параметр с ключевым словом out будет рассматриваться как выходной параметр
но на самом деле это самый простой ответ, который вы можете дать, поскольку он немного сложнее, чем указано здесь.