C#과 동등한 친구 클래스
이 자습서에서는 C#의 friend 클래스에 해당하는 항목에 대해 설명합니다. 먼저 프렌드 클래스와 C++ 예제를 사용하여 프로그래밍에 사용하는 방법에 대해 설명합니다.
다음으로 C#에 해당하는 friend 클래스가 없는 경우 대안을 살펴보겠습니다.
C++의 프렌드 클래스
객체 지향 프로그래밍에서 주로 적용되는 중요한 프로그래밍 기능은 데이터 은닉입니다. 클래스 외부에서 데이터 멤버를 숨기는 것은 클래스 내에서만 데이터 멤버를 업데이트할 수 있음을 의미합니다.
따라서 오직 하나의 클래스(데이터 멤버 보유)만이 데이터 멤버의 값을 변경할 수 있다고 말할 수 있습니다.
데이터를 숨기면 수정 중인 클래스를 테스트해야 하므로 테스트 범위가 줄어듭니다. 다른 클래스는 일부 클래스의 개인 데이터 멤버에 액세스할 수 없습니다. 따라서 코드가 수정되지 않은 경우 테스트할 필요가 없습니다.
때때로 데이터 은닉은 길고 복잡한 코드에서 약간 손상됩니다. 클래스는 일부 함수 또는 클래스를 친구로 선언할 수 있습니다.
이에 대한 응답으로 친구
기능과 친구
클래스는 개인 데이터 멤버에 액세스할 수 있습니다.
우정의 구문은 다음과 같습니다.
class ABC {
... friend class XYZ;
friend int change_data_member(int, char);
...
클래스 ABC
는 라인 #3에서 클래스 XYZ
를 친구로 선언합니다. 4번 줄은 friend
메서드를 선언하는 구문을 보여줍니다.
여기서 ABC
클래스는 change_data_member
메서드를 friend
함수로 선언합니다.
ABC
클래스로부터 우정 플래그를 수신한 후 XYZ
클래스의 모든 함수는 ABC
클래스의 개인 데이터 멤버에 액세스할 수 있습니다.
다만, 기능에 친목을 부여하는 경우에는 친목의 범위가 제한됩니다. 친구
기능(즉, 친구
로 선언됨)만이 우정 부여 클래스 구성원의 개인 데이터에 액세스할 수 있습니다.
C++에서 우정 개념의 구현을 봅시다.
#include <iostream>
using namespace std;
class ABC {
int privateMember;
public:
ABC(int privateMember) { this->privateMember = privateMember; }
friend int getPrivateMember(ABC &);
friend void setPrivateMember(ABC &, int);
};
int getPrivateMember(ABC &obj) { return obj.privateMember; }
void setPrivateMember(ABC &obj, int privateMember) {
obj.privateMember = privateMember;
}
int main() {
ABC abc(5);
cout << "Private Member: " << getPrivateMember(abc) << '\n';
setPrivateMember(abc, 7);
cout << "Private Member: " << getPrivateMember(abc) << '\n';
return 0;
}
이 코드에서 클래스 ABC
에는 프라이빗 데이터 멤버 privateMember
가 있습니다. 클래스 본문의 마지막 두 줄에서 두 개의 비클래스 함수인 getPrivateMember
및 setPrivateMember
에 우정이 부여됩니다.
이 코드의 출력은 다음과 같습니다.
Private Member: 5
Private Member: 7
프라이빗 데이터 멤버는 입력 및 출력 모두에 대해 액세스됩니다. 다음은 친구
클래스의 예입니다.
#include <iostream>
using namespace std;
class ABC {
int privateMember;
friend class DEF;
};
class DEF {
ABC abc;
public:
int getPrivateMember() { return abc.privateMember; }
void setPrivateMember(int privateMember) {
abc.privateMember = privateMember;
}
};
int main() {
DEF def;
def.setPrivateMember(12);
cout << "Private Member: " << def.getPrivateMember() << '\n';
return 0;
}
ABC
클래스의 두 번째 줄에서 DEF
클래스에 우정이 부여됩니다. 우정 상태가 있으면 DEF
클래스의 getPrivateMember
및 setPrivateMember
메소드는 ABC
클래스의 개인 구성원에 액세스할 수 있습니다.
이 코드의 출력은 다음과 같습니다.
Private Member: 12
이 친구
함수 또는 친구
클래스 개념은 C#이 아닌 C++에서 사용할 수 있습니다. 그러나 멤버가 아닌 데이터 함수에 액세스할 수 있는 몇 가지 방법이 있습니다.
Friend 클래스와 동등한 C# 사용
C#의 일부 비멤버 함수에서 모든 클래스의 데이터 멤버에 액세스하는 다양한 방법이 있습니다. 이에 대해 하나씩 논의해 보자.
중첩 클래스 사용
C++ 친구
클래스의 가장 가까운 C# 동등/대체는 중첩/내부 클래스를 생성하는 것입니다. 중첩 클래스는 외부 클래스의 전용 데이터 멤버에 액세스할 수 있습니다.
다음 예제에서는 Inner_class
클래스를 Outer_class
에 대한 중첩 클래스로 만듭니다. 포함하는 클래스의 범위 내에 있는 Inner_class
는 Outer_class
의 개인 멤버에 액세스할 수 있으므로 friend
클래스를 모방합니다.
using System;
public class Outer_class {
int privateMember;
Outer_class(int privateMember) {
this.privateMember = privateMember;
}
public class Inner_class {
public void innerClassFunction() {
Outer_class obj = new Outer_class(5);
Console.WriteLine("Private Member: " + obj.privateMember);
}
}
}
public class Driver {
static public void Main() {
Outer_class.Inner_class obj = new Outer_class.Inner_class();
obj.innerClassFunction();
}
}
위의 코드에는 하나의 외부 클래스와 하나의 내부 클래스가 있습니다. privateMember
변수는 외부 클래스의 전용 멤버입니다.
Inner_class
내부에서 외부 클래스의 privateMember
인 개인 데이터 멤버에 액세스하고 있습니다.
다음으로 Inner_class
개체를 생성한 Driver
클래스가 있습니다. Inner_class
개체를 사용하여 Inner_class
내부에서 innerClassFunction
을 호출합니다.
출력:
Private Member: 5
위의 코드는 문제 없이 빌드 및 실행되지만 여전히 아래 예제와 같이 부분 클래스 개념을 사용하여 Outer_class
와 Inner_class
를 구분하는 것이 좋습니다.
using System;
public partial class Outer_class {
int privateMember;
Outer_class(int privateMember) {
this.privateMember = privateMember;
}
}
public partial class Outer_class {
public class Inner_class {
public void innerClassFunction() {
Outer_class obj = new Outer_class(5);
Console.WriteLine("Private Member: " + obj.privateMember);
}
}
}
public class Driver {
static public void Main() {
Outer_class.Inner_class obj = new Outer_class.Inner_class();
obj.innerClassFunction();
}
}
Outer_class
의 두 번째 부분 클래스 정의에는 innerClassFunction
함수가 있습니다. 이 innerClassFunction
메소드는 외부 클래스의 객체를 생성합니다.
Outer_class
개체를 생성하는 동안 생성자 매개 변수에 대한 인수로 5
를 전달합니다. 이 생성자 매개변수는 아래 출력에서 볼 수 있듯이 외부 클래스의 첫 번째 부분 정의에서 데이터 멤버의 값이 됩니다.
Private Member: 5
부분 클래스는 여러 사람이 클래스의 다른 부분을 작성하는 대규모 프로젝트에서 중요합니다.
여기에서 우리는 이 부분 클래스 옵션을 이용하고 외부 클래스의 또 다른 부분 부분으로 내부에 Inner_class
를 작성하고 있습니다. 이 부분 체계는 부분 단위를 분리하여 유지할 수 있지만 단일 단위로 사용할 수 있습니다.
이 체계의 주요 이점은 실제 클래스 정의가 Inner_class
정의를 작성하는 사람에게 노출되지 않는다는 것입니다.
반사 객체
Reflection
객체를 사용하여 런타임 유형 정보를 얻을 수 있습니다.
프로그램 실행 중에 Reflection
객체를 사용하여 Type
정보를 얻을 수 있습니다. System.Reflection
네임스페이스는 실행 중인 프로그램의 메타데이터에 액세스하는 데 사용할 수 있습니다.
System.Reflection
은 런타임에 유용한 정보를 제공하고 다양한 유형, 값 및 클래스 개체를 프로그램에 추가하는 데 도움이 됩니다.
또한 System.Reflection
네임스페이스를 사용하여 메서드에 대한 핸들을 얻고 클래스의 전용 메서드를 테스트할 수 있습니다.
이런 식으로 클래스의 전용 메서드를 호출할 수 있습니다. 따라서 friend
클래스를 복제할 수 있습니다.
예를 들어 개인 메서드 callable_fun()
이 있는 다음 클래스를 가정합니다.
public class Class1 {
private char callable_fun() {
return 'C';
}
}
개인 함수 callable_fun
을 테스트하려면 다음 코드를 작성해야 합니다.
using System.Reflection;
public class Driver {
static public void Main() {
Class1 c = new Class1();
Type class1Type = c.GetType();
MethodInfo callMeMethod =
class1Type.GetMethod("callable_fun", BindingFlags.Instance | BindingFlags.NonPublic);
char result = (char)callMeMethod.Invoke(c, null);
Console.WriteLine("Output:" + result);
}
}
이 코드의 출력은 다음과 같습니다.
Output:C
Visual Studio Team System을 사용하는 경우 메서드를 마우스 오른쪽 버튼으로 클릭하고 Create Unit Tests...
를 선택하여 VS가 프라이빗 접근자로 프록시 클래스를 자동으로 생성하도록 할 수 있습니다.
InternalsVisibleToAttribute
클래스 사용
이 클래스는 일반적으로 현재 어셈블리 내에서만 볼 수 있는 유형에 대해 지정된 어셈블리에 대한 가시성을 향상시키는 데 도움이 됩니다.
// Syntax
[System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
public sealed class InternalsVisibleToAttribute : Attribute
두 개의 서명되지 않은 어셈블리가 있는 경우 InternalsVisibleToAttribute
클래스는 다른 서명되지 않은 어셈블리에서 하나의 서명되지 않은 어셈블리의 전용 멤버에 액세스하는 데 도움이 됩니다. 한 어셈블리의 이름(friend
클래스/어셈블리의 이름을 가짐)이 인수로 전달됩니다.
다음으로 InternalsVisibleToAttribute
가 서명되지 않은 다른 어셈블리의 전용 멤버에 액세스하는 데 사용되는 예를 살펴보겠습니다. 여기서 SecondClass
는 FirstClass
의 전용 멤버에 액세스합니다.
아래 코드를 참조하십시오.
using System;
using System.Runtime.CompilerServices;
using Utilities.Example;
[assembly:InternalsVisibleToAttribute("FirstClass")]
namespace Utilities.Example {
public class FirstClass {
internal static int InnerMethod(int x) {
return x * x;
}
}
}
다음 예제는 SecondClass
어셈블리의 소스 코드를 제공합니다.
public class SecondClass {
public static void Main() {
Console.WriteLine(FirstClass.InnerMethod(10));
}
}
이 코드의 출력은 100
입니다.
서명된 어셈블리가 있는 경우 디렉터리 경로와 파일 이름 확장명이 필요하지 않습니다.
다음 예제에서는 InternalsVisibleToAttribute
를 사용하여 다른 서명된 어셈블리에 표시되는 서명된 어셈블리에서 innerMethod
라는 프라이빗 메서드를 호출합니다. 내부 innerMethod
메서드를 포함하는 FirstClass
클래스를 정의합니다.
using System;
using System.IO;
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo(
"Friend_Assembly, PublicKey=002400000480000094" + "0000000602000000240000525341310004000" +
"001000100bf8c25fcd44838d87e245ab35bf7" + "3ba2615707feea295709559b3de903fb95a93" +
"3d2729967c3184a97d7b84c7547cd87e435b5" + "6bdf8621bcb62b59c00c88bd83aa62c4fcdd4" +
"712da72eec2533dc00f8529c3a0bbb4103282" + "f0d894d5f34e9f0103c473dce9f4b457a5dee" +
"fd8f920d8681ed6dfcb0a81e96bd9b176525a" + "26e0b3")]
public class FirstClass {
internal static int innerMethod(int x) {
return x * x;
}
}
다음 예제가 Friend_Assembly
라는 강력한 이름의 어셈블리로 컴파일된다고 가정합니다. FirstClass
의 내부 메소드는 innerMethod
를 성공적으로 호출하지만 메소드는 FirstClass
내부에 있습니다.
public class SecondClass {
public static void Main() {
int result = FirstClass.innerMethod(10);
Console.WriteLine(result);
}
}
이 코드의 출력은 다시 100
입니다.
우리는 C#에서 C++ friend
클래스의 다른 등가물을 제시했습니다. 독자는 요구 사항에 따라 무엇이든 사용할 수 있습니다.