함수로 수정할 수 있도록 개체를 전달해야하는 함수를 만들고 있습니다. 차이점은 무엇입니까?
public void myFunction(ref MyClass someClass)
과
public void myFunction(out MyClass someClass)
어떤 것을 사용해야하며 그 이유는 무엇입니까?
ref
함수에 들어가기 전에 객체가 초기화되었다는 것을 컴파일러에 알려주는 반면,out
객체가 함수 내부에서 초기화된다는 것을 컴파일러에 알립니다.
그러면서ref
양방향입니다.out
out-only입니다.
그만큼ref
수정자는 다음을 의미합니다.
그만큼out
수정자는 다음을 의미합니다.
out
메서드가 호출되기 전에 초기화 된 경우 해당 메서드에서 설정하기 전에 메서드 내에서 전혀 읽을 수 있습니까? 호출 된 메서드가 호출하는 메서드가 인수로 전달한 것을 읽을 수 있습니까? - Panzercrisis
Dom이 TPS 보고서에 대한 메모에 대해 Peter의 방에 나타났습니다.
돔이 논쟁의 여지가 있다면 그는 메모 사본을 인쇄 할 것입니다.
돔이 논쟁 거리가된다면, 그는 피터에게 그가 가지고 갈 수있는 새로운 메모 사본을 인쇄하게 할 것입니다.
나는 설명에서 내 손을 시험 할 것이다 :
가치 유형이 올바르게 작동하는 방식을 이해하고 있다고 생각합니다. 값 유형은 (int, long, struct 등)입니다. ref 명령을 사용하지 않고 함수를 전송하면데이터. 함수에서 해당 데이터에 대해 수행하는 작업은 원본이 아닌 복사본에만 적용됩니다. ref 명령은 ACTUAL 데이터를 보내고 변경 사항은 함수 외부의 데이터에 영향을 미칩니다.
좋아, 참조 형식에 대한 혼란스러운 부분은 다음과 같습니다.
참조 유형을 만들 수 있습니다.
List<string> someobject = new List<string>()
새로 시작할 때일부 대상두 부분이 생성됩니다.
이제 네가 보낼 때.일부 대상그것을 참조하지 않고 메서드에 복사합니다.참고포인터가 아니라 데이터. 그래서 당신은 지금 이것을 가지고 있습니다 :
(outside method) reference1 => someobject
(inside method) reference2 => someobject
동일한 객체를 가리키는 두 개의 참조입니다. 에 대한 속성을 수정하면일부 대상reference2를 사용하면 reference1이 가리키는 동일한 데이터에 영향을줍니다.
(inside method) reference2.Add("SomeString");
(outside method) reference1[0] == "SomeString" //this is true
reference2를 null로 설정하거나 새 데이터를 가리키면 reference1에는 영향을 미치지 않으며 reference1에는 데이터가 가리 킵니다.
(inside method) reference2 = new List<string>();
(outside method) reference1 != null; reference1[0] == "SomeString" //this is true
The references are now pointing like this:
reference2 => new List<string>()
reference1 => someobject
이제 당신이 보낼 때 어떻게됩니까?일부 대상방법으로 심판에 의해? 그만큼실제 참조에일부 대상메서드에 전송됩니다. 이제 데이터에 대한 참조가 하나만 있습니다.
(outside method) reference1 => someobject;
(inside method) reference1 => someobject;
그러나 이것은 무엇을 의미합니까? 그것은 정확하게 두 가지 주요 사항을 제외하고 ref로가 아니라 someobject를 보내는 것과 같습니다.
1) 메서드 내에서 참조를 null로 설정하면 메서드 외부의 참조가 null이됩니다.
(inside method) reference1 = null;
(outside method) reference1 == null; //true
2) 이제 완전히 다른 데이터 위치에 대한 참조를 가리킬 수 있으며 함수 외부의 참조는 이제 새 데이터 위치를 가리 킵니다.
(inside method) reference1 = new List<string>();
(outside method) reference1.Count == 0; //this is true
ref
과out
매개 변수. - Joyce Babuout
예어? - Asif Mushtaq
너는 다음을 사용해야한다.out
귀하의 요구 사항이 만족 스러울 때마다 선호합니다.
C #에서는 메서드가 하나의 값만 반환 할 수 있습니다. 둘 이상의 값을 반환하려는 경우 out 키워드를 사용할 수 있습니다. 아웃 수정자는 리턴 참조별로 리턴합니다. 가장 간단한 대답은 메서드에서 값을 가져 오는 데 "out"이라는 키워드가 사용된다는 것입니다.
C #에서는 int, float, double 등과 같은 값 형식을 메서드 매개 변수의 인수로 전달하면 값에 의해 전달됩니다. 따라서 매개 변수 값을 수정하면 메서드 호출의 인수에 영향을 미치지 않습니다. 그러나 "ref"키워드로 매개 변수를 표시하면 실제 변수에 반영됩니다.
Dog Extending, Cat 예제. ref를 사용하는 두 번째 메소드는 호출자가 참조하는 객체를 변경합니다. 그러므로 "고양이"!!!
public static void Foo()
{
MyClass myObject = new MyClass();
myObject.Name = "Dog";
Bar(myObject);
Console.WriteLine(myObject.Name); // Writes "Dog".
Bar(ref myObject);
Console.WriteLine(myObject.Name); // Writes "Cat".
}
public static void Bar(MyClass someObject)
{
MyClass myTempObject = new MyClass();
myTempObject.Name = "Cat";
someObject = myTempObject;
}
public static void Bar(ref MyClass someObject)
{
MyClass myTempObject = new MyClass();
myTempObject.Name = "Cat";
someObject = myTempObject;
}
참조 유형 (클래스)을 전달하기 때문에 사용할 필요가 없습니다.ref
왜냐하면 기본적으로참고실제 개체에 전달되므로 항상 참조 뒤에 개체를 변경합니다.
예:
public void Foo()
{
MyClass myObject = new MyClass();
myObject.Name = "Dog";
Bar(myObject);
Console.WriteLine(myObject.Name); // Writes "Cat".
}
public void Bar(MyClass someObject)
{
someObject.Name = "Cat";
}
수업을 들으면 오랫동안 사용할 필요가 없습니다.ref
메서드 내에서 개체를 변경하려는 경우
ref
과out
뒤에 오는 다름을 제외하면 유사하게 행동하십시오.
ref
변수는 사용 전에 초기화해야합니다.out
할당없이 변수를 사용할 수있다.out
매개 변수는이를 사용하는 함수에 의해 할당되지 않은 값으로 처리되어야합니다. 그래서 우리는 초기화 된out
매개 변수를 호출하지만 함수가 실행될 때 값이 손실됩니다.
"빵 굽는 사람"
이는 첫 번째 문자열 참조가 "Baker"를 가리 키도록 변경하기 때문입니다. ref 키워드 (=> 문자열 참조에 대한 참조)를 통해 전달 했으므로 참조를 변경할 수 있습니다. 두 번째 호출은 문자열에 대한 참조 복사본을 가져옵니다.
문자열은 처음에는 특별한 것으로 보입니다. 하지만 문자열은 참조 클래스 일 뿐이며 정의하면
string s = "Able";
그런 다음 s는 "Able"이라는 텍스트가 포함 된 문자열 클래스에 대한 참조입니다! 동일한 변수에 대한 다른 지정
s = "Baker";
원래 문자열을 변경하지 않고 새로운 인스턴스를 만들고 그 인스턴스를 가리키게합니다!
다음과 같은 간단한 코드 예제로 시도해 볼 수 있습니다.
string s = "Able";
string s2 = s;
s = "Baker";
Console.WriteLine(s2);
너는 무엇을 기대 하느냐? s2가 원래 인스턴스를 가리키고있는 동안 s의 참조를 다른 인스턴스로 설정하기 때문에 얻을 수있는 것은 여전히 "에이블"입니다.
편집하다: string은 또한 변경할 수 없습니다. 즉 기존의 문자열 인스턴스를 수정하는 메서드 나 속성이 없습니다. (문서에서 하나를 찾으려고 할 수는 있지만 아무 것도하지 않습니다 .-)). 모든 문자열 조작 메소드는 새로운 문자열 인스턴스를 반환합니다! (그런 이유로 StringBuilder 클래스를 사용할 때 종종 더 나은 성능을 얻습니다)
예 (나 같은)로 배우는 사람들은안토니 콜레 쇼프 (Anthony Kolesov).
요점을 설명하기 위해 ref, out 및 다른 몇 가지 예제를 만들었습니다. 차이점을 이해하기위한 모범 사례는 다루지 않고 있습니다.
아웃:return 문은 함수에서 하나의 값만 반환하는 데 사용할 수 있습니다. 그러나 출력 매개 변수를 사용하면 함수에서 두 개의 값을 반환 할 수 있습니다. 출력 매개 변수는 참조 매개 변수와 비슷하지만 데이터가 아닌 메서드에서 데이터를 전송한다는 점만 다릅니다.
다음 예는 이것을 설명합니다.
using System;
namespace CalculatorApplication
{
class NumberManipulator
{
public void getValue(out int x )
{
int temp = 5;
x = temp;
}
static void Main(string[] args)
{
NumberManipulator n = new NumberManipulator();
/* local variable definition */
int a = 100;
Console.WriteLine("Before method call, value of a : {0}", a);
/* calling a function to get the value */
n.getValue(out a);
Console.WriteLine("After method call, value of a : {0}", a);
Console.ReadLine();
}
}
}
심판 :참조 매개 변수는 변수의 메모리 위치에 대한 참조입니다. 참조로 매개 변수를 전달하면 값 매개 변수와 달리 이러한 매개 변수에 대해 새 저장 위치가 만들어지지 않습니다. 참조 매개 변수는 메소드에 제공되는 실제 매개 변수와 동일한 메모리 위치를 나타냅니다.
C #에서는 ref 키워드를 사용하여 참조 매개 변수를 선언합니다. 다음 예제에서는이를 보여줍니다.
using System;
namespace CalculatorApplication
{
class NumberManipulator
{
public void swap(ref int x, ref int y)
{
int temp;
temp = x; /* save the value of x */
x = y; /* put y into x */
y = temp; /* put temp into y */
}
static void Main(string[] args)
{
NumberManipulator n = new NumberManipulator();
/* local variable definition */
int a = 100;
int b = 200;
Console.WriteLine("Before swap, value of a : {0}", a);
Console.WriteLine("Before swap, value of b : {0}", b);
/* calling a function to swap the values */
n.swap(ref a, ref b);
Console.WriteLine("After swap, value of a : {0}", a);
Console.WriteLine("After swap, value of b : {0}", b);
Console.ReadLine();
}
}
}
ref 및 out 작업은 참조로 전달하고 C ++ 에서처럼 포인터로 전달하는 것과 같습니다.
ref의 경우, 인수는 선언되고 초기화되어야합니다.
out의 경우, 인수는 선언되어야하지만 초기화 될 수도 있고 초기화되지 않을 수도 있습니다.
double nbr = 6; // if not initialized we get error
double dd = doit.square(ref nbr);
double Half_nbr ; // fine as passed by out, but inside the calling method you initialize it
doit.math_routines(nbr, out Half_nbr);
out double Half_nbr
. - Sebastian Hofmann
심판ref 매개 변수의 값이 이미 설정되어 있으면이 메서드에서 값을 읽고 수정할 수 있음을 나타냅니다. ref 키워드를 사용하는 것은 호출자가 매개 변수의 값을 초기화 할 책임이 있다고 말하는 것과 같습니다.
아웃컴파일러에게 객체의 초기화가 이 함수는 out 매개 변수에 함수를 할당해야합니다. 할당되지 않은 상태로 둘 수는 없습니다.
제작 시간 :
(1) 호출 메소드를 만든다.Main()
(2) List 객체 (참조 유형 객체)를 생성하여 변수에 저장합니다myList
.
public sealed class Program
{
public static Main()
{
List<int> myList = new List<int>();
런타임 중 :
(3) 런타임은 #00에 스택에 메모리를 할당하고 주소를 저장할 수있을 정도로 넓습니다 (#00 =myList
왜냐하면 변수 이름은 실제로 메모리 위치의 별칭이기 때문입니다.
(4) 런타임은 메모리 위치 #FF의 힙에리스트 객체를 생성합니다 (이 모든 주소는 예를 들어 sake입니다)
(5) 그런 다음 런타임은 #00에 객체의 시작 주소 #FF를 저장합니다 (또는 단어로 포인터에 List 객체의 참조를 저장합니다.myList
)
제작 시간으로 돌아 가기 :
(6) 그런 다음 List 객체를 인수로 전달합니다myParamList
호출 된 메소드에modifyMyList
새 List 객체를 할당합니다.
List<int> myList = new List<int>();
List<int> newList = ModifyMyList(myList)
public List<int> ModifyMyList(List<int> myParamList){
myParamList = new List<int>();
return myParamList;
}
런타임 중 :
(7) 런타임은 호출 된 메소드의 호출 루틴을 시작하고 그 일부로 매개 변수의 유형을 점검합니다.
(8) 참조 유형을 찾으면 #04에서 스택에 메모리를 할당하여 매개 변수 변수의 별명을 지정합니다myParamList
.
(9) 그런 다음 #FF 값을 저장합니다.
(10) 런타임은 메모리 위치 #004에서 힙에 목록 객체를 만들고이 값으로 #04의 #FF를 대체합니다 (또는 원래 List 객체를 참조 해제하고이 메소드에서 새 List 객체를 가리킴)
#00의 주소는 변경되지 않고 #FF에 대한 참조를 유지합니다 (또는 원본myList
포인터가 방해받지 않는다).
그만큼심판키워드는 (8)과 (9)에 대한 런타임 코드 생성을 건너 뛰는 컴파일러 지시문으로, 메서드 매개 변수에 대한 힙 할당이 없음을 의미합니다. 원래 #00 포인터를 사용하여 #FF에있는 오브젝트를 조작합니다. 원래 포인터가 초기화되지 않은 경우 런타임은 변수가 초기화되지 않았기 때문에 진행할 수 없다는 불평을 중지합니다
그만큼아웃keyword는 (9)와 (10)을 약간 수정 한 ref와 거의 같은 컴파일러 지시문입니다. 컴파일러는 인수가 초기화되지 않았으며 (8), (4) 및 (5)를 계속 사용하여 힙에 객체를 만들고 인수 주소에 시작 주소를 저장합니다. 초기화되지 않은 오류가 발생하지 않으며 저장된 이전 참조가 손실됩니다.
그들은 거의 동일합니다. 유일한 차이점은 out 매개 변수로 전달하는 변수를 초기화 할 필요가 없으며 ref 매개 변수를 사용하는 메서드는이를 설정해야한다는 것입니다.
int x; Foo(out x); // OK
int y; Foo(ref y); // Error
Ref 매개 변수는 수정할 수있는 데이터를위한 것이고, 매개 변수는 이미 반환 값을 무언가로 사용하고있는 함수 (예 : int.TryParse)에 대한 추가 출력 데이터입니다.
public static void Main(string[] args)
{
//int a=10;
//change(ref a);
//Console.WriteLine(a);
// Console.Read();
int b;
change2(out b);
Console.WriteLine(b);
Console.Read();
}
// static void change(ref int a)
//{
// a = 20;
//}
static void change2(out int b)
{
b = 20;
}
이 코드를 확인하면 완전한 차이를 설명 할 수 있습니다. "ref"를 사용할 때 u가 이미 int / string을 초기화한다는 것을 의미합니다.
그러나 "out"을 사용할 때 그것은 두 조건에서 작동 wheather 유 int / 문자열 또는 초기화하지 하지만 그 함수에서 int / string을 초기화해야합니다.
참고 : ref 키워드는 인수를 참조로 전달하는 데 사용됩니다. 즉, 메소드에서 해당 매개 변수의 값이 변경되면 호출 메소드에 반영됩니다. ref 키워드를 사용하여 전달 된 인수는 호출 된 메소드에 전달되기 전에 호출 메소드에서 초기화되어야합니다.
아웃: out 키워드는 또한 ref 키워드와 같은 인수를 전달하는데도 사용되지만 값을 할당하지 않고 인수를 전달할 수 있습니다. out 키워드를 사용하여 전달 된 인수는 호출 된 메소드로 초기화되기 전에 호출 된 메소드에서 초기화되어야합니다.
public class Example
{
public static void Main()
{
int val1 = 0; //must be initialized
int val2; //optional
Example1(ref val1);
Console.WriteLine(val1);
Example2(out val2);
Console.WriteLine(val2);
}
static void Example1(ref int value)
{
value = 1;
}
static void Example2(out int value)
{
value = 2;
}
}
/* Output 1 2
메서드 오버로딩에서 참조 및 출력
ref와 out은 동시에 메서드 오버로딩에 사용할 수 없습니다. 그러나 ref 및 out은 런타임에 다르게 처리되지만 컴파일 타임에 동일하게 처리됩니다 (CLR은 ref 및 out을 위해 IL을 작성하는 동안 두 개를 구별하지 않습니다).
아래에서는 두 가지 모두를 사용한 예제를 보여 줬습니다.참조과아웃. 자, 여러분 모두는 심판에 대해 밝혀 질 것입니다.
아래에 언급 된 예에서 내가 코멘트 할 때// myRefObj = new myClass {Name = "외부 참조 요청 !!"}};줄에 오류가 발생합니다."할당되지 않은 지역 변수 'myRefObj'사용", 그런 오류는 없습니다.아웃.
Ref 사용 위치: in 매개 변수를 사용하여 프로 시저를 호출 할 때 동일한 매개 변수가 해당 proc의 출력을 저장하는 데 사용됩니다.
사용 장소 :매개 변수가없는 프로 시저를 호출하면 동일한 매개 변수가 해당 프로 시저의 값을 반환하는 데 사용됩니다. 출력에주의하십시오.
public partial class refAndOutUse : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
myClass myRefObj;
myRefObj = new myClass { Name = "ref outside called!! <br/>" };
myRefFunction(ref myRefObj);
Response.Write(myRefObj.Name); //ref inside function
myClass myOutObj;
myOutFunction(out myOutObj);
Response.Write(myOutObj.Name); //out inside function
}
void myRefFunction(ref myClass refObj)
{
refObj.Name = "ref inside function <br/>";
Response.Write(refObj.Name); //ref inside function
}
void myOutFunction(out myClass outObj)
{
outObj = new myClass { Name = "out inside function <br/>" };
Response.Write(outObj.Name); //out inside function
}
}
public class myClass
{
public string Name { get; set; }
}
파라미터를 수신하는 방법의 관점에서,ref
과out
C #은 모든 메소드가 모든 메소드에 쓰기를 요구한다는 것입니다.out
매개 변수를 전달하기 전에 반환해야하며, 매개 변수로 전달하는 것 이외의 다른 매개 변수를 사용해서는 안됩니다.out
매개 변수로 전달하거나 매개 변수로 전달할 때까지out
매개 변수를 다른 방법으로 보내거나 직접 작성하십시오. 일부 다른 언어는 이러한 요구 사항을 부과하지 않습니다. C #에서 선언 된 가상 또는 인터페이스 메소드.out
매개 변수는 이러한 매개 변수에 특별한 제한을 두지 않는 다른 언어로 겹쳐 쓸 수 있습니다.
호출자의 관점에서 볼 때 C #은 많은 경우에out
매개 변수는 전달 된 변수가 먼저 읽히지 않고 기록되게합니다. 이 가정은 다른 언어로 작성된 메소드를 호출 할 때 올바르지 않을 수 있습니다. 예 :
struct MyStruct
{
...
myStruct(IDictionary<int, MyStruct> d)
{
d.TryGetValue(23, out this);
}
}
만약myDictionary
~을 식별하다IDictionary<TKey,TValue>
C #이외의 언어로 작성된 구현MyStruct s = new MyStruct(myDictionary);
임무처럼 보이면 잠재적으로 떠날 수 있습니다.s
수정되지 않은.
VB.NET으로 작성된 생성자는 C #의 경우와 달리 호출 된 메서드에서out
매개 변수를 지정하고 모든 필드를 무조건 지 웁니다. 위에 언급 한 이상한 행동은 VB에서 전체적으로 또는 C #으로 완전히 작성된 코드에서는 발생하지 않지만 C #으로 작성된 코드가 VB.NET으로 작성된 메서드를 호출 할 때 발생할 수 있습니다.
매개 변수를 ref로 전달하려면 함수에 매개 변수를 전달하기 전에 매개 변수를 초기화해야합니다. 다른 컴파일러에서는 오류를 표시합니다. 그러나 out 매개 변수의 경우 객체 매개 변수를 전달하기 전에 객체 매개 변수를 초기화 할 필요가 없습니다. 메서드를 호출 할 수 있습니다. 호출 메서드 자체에서 개체를 초기화 할 수 있습니다.
나는 놀고 있었다.ref
이 예제가 꽤 흥미 롭다는 것을 알게되었습니다.
나는RefEater(ref s1);
두 번째 주석 처리 된 경우와 같이 빌드 오류가 발생하지만s1
필드는 생성자가 호출되기 전에 기본값으로 초기화됩니다.https://stackoverflow.com/a/1920659/5612780).
public class Class1
{
// this will have the default value
private string s1;
public Class1()
{
// no issue here..
RefEater(ref s1);
// Error CS0165 Use of unassigned local variable 's2'
//string s2;
//RefEater(ref s2);
}
private void RefEater(ref string s)
{
}
}
나는 이것에 대해서는별로 좋지 않을 수도 있지만, 확실하게 문자열 (비록 기술적으로 참조 형이고 힙에 살지만)은 참조가 아니라 값으로 전달됩니까?
string a = "Hello";
string b = "goodbye";
b = a; //attempt to make b point to a, won't work.
a = "testing";
Console.WriteLine(b); //this will produce "hello", NOT "testing"!!!!
이 때문에 함수의 범위를 벗어나는 변경 사항을 원할 경우 ref가 필요합니다. 그렇지 않은 경우에는 참조를 전달하지 않습니다.
지금까지 내가 아는 한 struct / value 유형과 문자열 자체에 대한 ref 만 필요합니다. string은 값 유형이 아니지만 위조하는 참조 유형입니다.
나는 완전히 여기에서 틀릴 수 있었다, 나는 새롭다.
Capitalize()
문자열의 내용을 대문자로 바꿉니다. 너가 그 때 너의 선을 대체하면a = "testing";
와a.Capitalize();
출력은 "Hello"가 아닌 "HELLO"가됩니다. 변경할 수없는 형식의 장점 중 하나는 참조를 전달할 수 있으며 값을 변경하는 다른 코드에 대해 걱정할 필요가 없다는 것입니다. - Don Kirkby
함수 내부에서 전달되는 참조 매개 변수가 직접적으로 작동한다는 것을 명심하십시오.
예를 들어,
public class MyClass
{
public string Name { get; set; }
}
public void Foo()
{
MyClass myObject = new MyClass();
myObject.Name = "Dog";
Bar(myObject);
Console.WriteLine(myObject.Name); // Writes "Dog".
}
public void Bar(MyClass someObject)
{
MyClass myTempObject = new MyClass();
myTempObject.Name = "Cat";
someObject = myTempObject;
}
이것은 고양이가 아니라 개를 쓸 것입니다. 따라서 someObject에 직접 작업해야합니다.
MyClass
~ 될 것입니다.class
타입, 즉 참조 타입이다. 이 경우 전달하는 객체는myFunction
아무리해도ref
/out
예어.myFunction
~을받을 것이다.새로운참조를 가리키는 참조같은객체로 만들 수 있으며 원하는만큼 객체를 수정할 수 있습니다. 차이점은ref
키워드를 사용하면myFunction
받은같은동일한 객체에 대한 참조. 그것은 중요한 경우에만myFunction
포인트를 가리키는 참조를 변경했다.다른목적. - Jeppe Stig Nielsen