예외처리의 간결함의 입장에서 Try~(+out) 와같은 함수를 선호하기 시작했습니다.
단 이경우 함수가 예외처리를 완벽하게 해야하며 값을 안전하게 사용할수 있다란 보장값을 true를
통해 전달해줄수있기때문에(함수는 하나밖에 반환못하는 단점을 극복)
호출자가 null체크,예외발생코드등을 작성안해도 되기때문입니다.
장점 1줄 요약 :호출자에게 예외처리를 떠넘기지 않을수 있다.
out 키워드단점이라기보다, 함수가 인자값을 변형시킬수 있다란것은 함수형프로그래밍 불변성( 객체를 변하게함으로 발생하는 여러가지문제) 과 비교해야하는 것으로 보입니다.
out은 ref, in과 마찬가지로 값형을 반환할 때 유용합니다. 사이즈가 있는 값형을 반환할 때 in/out/ref 를 씁니다.
Try~ 로 시작하는 메소드는 예외를 발생하지 않고 반환값을 bool형인 성공/실패로 처리하고자 할 때 좋습니다. 반환값을 out으로 인자로 반환합니다.
인자에 out을 쓰게 되면, 코딩하다보면 복수개의 값을 반환할 때 여러개의 인자에 out을 쓰고 싶은 유혹?이 생기는데요, 함수는 의미있는 하나의 결과값을 반환하는게 잘 설계된 것이라 할 수 있으므로, 그런것만 유의하면, out 인자는 상황에 따라 적극적으로 써도 무방할 듯 합니다.
하지만 장기적으로 볼때는 좋은 방법은 아니라 생각합니다. input 객체를 받아 output 객체를 반환하는 방식이 개방 폐쇄 원칙 을 가장 잘 지키는 메소드 모델링이라고 생각합니다. out을 통해 메소드를 수정하여 유지보수를 하게되면 인터페이스를 쓰는 경우 같이 수정해줘야하며 다른 메서드를 사용하는 부분까지 수정해야 합니다. 반면 input 객체를 만들어서 개발한다면, 처음 개발할 때는 POCO 모델 클래스를 만들어줘야하니까 귀찮을 수 있고 파일이 늘어나겠지만, 메서드 수정없이 Input 객체에 Property만 추가해준다면 input 요소의 수도 얼마든지 늘릴 수 있습니다.
input output 객체 없이 원시자료형으로만 사용하는 메소드라면야 사용해도 무방할 듯하지만 사용자 객체를 받는 경우라면 남발하는 것은 개방 폐쇄 원칙을 어길 위험이 있어 지양 해야한다고 생각합니다.
public int intReturn(string asdf, out int rtnOut)
{
...생략...
rtnOut = 10;
return 20;
}
// 유지 보수 발생1
public int intReturn(string asdf, out int rtnOut, out int rtnOut1)
{
...생략...
rtnOut = 10;
rtnOut1 = 30;
return 20;
}
// 유지 보수 발생2
public int intReturn(string asdf, out int rtnOut, out int rtnOut1, out int rtnOut2)
{
...생략...
rtnOut = 10;
rtnOut1 = 30;
rtnOut2 = 40;
return 20;
}
이런식으로 하면서 메서드에서 계속 리턴에 데이터를 추가할 일이 생기면 out out out out…늘어나겠죠.
그냥 그렇게 안하기 위해 클래스로 만들어서 코드 가독성을 높이고 개방폐쇄 원칙을 지키는 것입니다.
개방 폐쇄 원칙에 대해 이론을 읽어보시면 메소드에 대하여 깔끔하게 닫히고 깔끔하게 확장되는 구조인데요. 그럴려면 Input 클래스와 Output 클래스를 만드는 방법말고는 없습니다.
public class reqInput
{
public int data1 {get; set;}
public string data2 {get; set;}
}
public class resOutput
{
public int rtnOut {get; set;}
}
public resOutput intReturn(reqInput input)
{
...생략...
return resOutput;
}
//유지보수 발생1
public class reqInput
{
public int data1 {get; set;}
public string data2 {get; set;}
public int data3 {get;set;}
}
public class resOutput
{
public int rtnOut {get; set;}
}
public resOutput intReturn(reqInput input)
{
...생략...
return resOutput;
}
//유지보수 발생2
public class reqInput
{
public int data1 {get; set;}
public string data2 {get; set;}
public int data3 {get;set;}
public int data4 {get;set;}
}
public class resOutput
{
public int rtnOut {get; set;}
}
public resOutput intReturn(reqInput input)
{
...생략...
return resOutput;
}
보시면 두번째 예제는 input class에 property만 추가해주고 메서드는 변형이 없죠.
그냥 이렇게하면 말씀드린대로 처음은 귀찮을 수 있어도 유지보수가 용이하다는 것입니다. intReturn 메소드를 참조하는 Interface나 class에 대하여 일일히 수정하고 다니지 않아도 input 모델을 받고 있으므로 거기에 property로 요소만 추가해주면 쓸 일이 없는 곳에서는 데이터를 안쓰면 되는거고, 필요한 곳에서는 input class로 인해 확장성이 용이해졌으니 거기에 추가만 해서 쓰면 되는 것입니다.
예전에는 메서드 내부의 상태를 명시적으로 output 하기 위해 간단하게 쓰였는데
이제는 복잡하기 만한 out 키워드는 사용을 지양해야 하지 않을까 싶습니다.
결과가 필요하면 클래스로 받던지, 아니면 튜플을 이용하는 방법으로요.
개인적으로 튜플이 지원되면서 레거시 문법으로 전락했다고 생각됩니다.