이 문서에서는 .NET Framework가 C# 및 Visual Basic 코드에서 Windows 런타임 또는 Windows 런타임 구성 요소에서 제공하는 개체에 대한 호출을 처리하는 방법을 설명합니다.
.NET Framework에서는 특수 처리 없이 기본적으로 여러 스레드에서 모든 개체에 액세스할 수 있습니다. 개체에 대한 참조만 있으면 됩니다. Windows 런타임에서 이러한 개체는 민첩한
가능한 경우 CLR(공용 언어 런타임)은 Windows 런타임과 같은 다른 원본의 개체를 .NET Framework 개체인 것처럼 처리합니다.
개체가 IAgileObject 인터페이스를 구현하거나 MarshalingBehaviorAttribute 특성에 MarshalingType.Agile이(가) 있는 경우 CLR은 이를 유연한 객체로 처리합니다.
CLR이 호출이 발생한 스레드에서 대상 개체의 스레딩 컨텍스트로 호출을 마샬링할 수 있는 경우, 이를 투명하게 처리합니다.
개체에 MarshalingBehaviorAttribute 특성과 MarshalingType.None가 있을 경우, 클래스는 마샬링 정보를 제공하지 않습니다. CLR은 호출을 처리할 수 없으므로, 개체가 생성된 스레딩 컨텍스트에서만 사용할 수 있다는 메시지와 함께 InvalidCastException 예외를 발생시킵니다.
다음 섹션에서는 이 동작이 다양한 원본의 개체에 미치는 영향에 대해 설명합니다.
C# 또는 Visual Basic으로 작성된 Windows 런타임 구성 요소의 개체
활성화할 수 있는 구성 요소의 모든 형식은 기본적으로 Agile입니다.
비고
민첩성이 스레드 안전을 의미하지는 않습니다. Windows 런타임과 .NET Framework 모두에서 대부분의 클래스는 스레드로부터 안전하지 않습니다. 이는 스레드 보안이 성능 비용이 발생하기 때문이며, 대부분의 객체가 여러 스레드로부터 액세스되지 않기 때문입니다. 필요에 따라 개별 개체에 대한 액세스를 동기화하거나 스레드로부터 안전한 클래스를 사용하는 것이 더 효율적입니다.
Windows 런타임 구성 요소를 작성할 때 기본값을 재정의할 수 있습니다. ICustomQueryInterface 인터페이스 및 IAgileObject 인터페이스를 참조하세요.
Windows 런타임의 개체
Windows 런타임의 대부분의 클래스는 민첩하며 CLR은 이를 Agile로 처리합니다. 이러한 클래스에 대한 설명서에는 클래스 특성 중 "MarshalingBehaviorAttribute(Agile)"가 나열됩니다. 이러한 유연한 클래스 중 일부의 멤버, 예를 들어 XAML 컨트롤, UI 스레드에서 호출되지 않으면 예외를 발생시킵니다. 예를 들어 다음 코드는 백그라운드 스레드를 사용하여 클릭한 단추의 속성을 설정하려고 합니다. 단추의 Content 속성이 예외를 발생시킵니다.
private async void Button_Click_2(object sender, RoutedEventArgs e)
{
Button b = (Button) sender;
await Task.Run(() => {
b.Content += ".";
});
}
Private Async Sub Button_Click_2(sender As Object, e As RoutedEventArgs)
Dim b As Button = CType(sender, Button)
Await Task.Run(Sub()
b.Content &= "."
End Sub)
End Sub
Dispatcher 속성 또는 UI 스레드의 컨텍스트에 있는 개체의 Dispatcher
속성을 사용하여 단추에 안전하게 액세스할 수 있습니다(예: 단추가 있는 페이지). 다음 코드는 CoreDispatcher 개체의 RunAsync 메서드를 사용하여 UI 스레드에서 호출을 디스패치합니다.
private async void Button_Click_2(object sender, RoutedEventArgs e)
{
Button b = (Button) sender;
await b.Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() => {
b.Content += ".";
});
}
Private Async Sub Button_Click_2(sender As Object, e As RoutedEventArgs)
Dim b As Button = CType(sender, Button)
Await b.Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
Sub()
b.Content &= "."
End Sub)
End Sub
비고
Dispatcher
속성은 다른 스레드에서 호출될 때 예외를 throw하지 않습니다.
UI 스레드에서 만든 Windows 런타임 개체의 수명은 스레드의 수명에 의해 제한됩니다. 창이 닫힌 후에는 UI 스레드의 개체에 액세스하지 마세요.
XAML 컨트롤을 상속하거나 XAML 컨트롤 집합을 작성하여 고유한 컨트롤을 만드는 경우 컨트롤은 .NET Framework 개체이므로 민첩합니다. 그러나 기본 클래스 또는 구성 요소 클래스의 멤버를 호출하거나 상속된 멤버를 호출하는 경우, 해당 멤버는 UI 스레드 외의 모든 스레드에서 호출될 때 예외를 throw합니다.
마샬링할 수 없는 클래스
마샬링 정보를 제공하지 않는 Windows 런타임 클래스에는 MarshalingType.NoneMarshalingBehaviorAttribute 특성이 있습니다. 이러한 클래스에 대한 설명서에는 특성 중 "MarshalingBehaviorAttribute(None)"가 나열됩니다.
다음 코드는 UI 스레드에 CameraCaptureUI 개체를 만든 다음 스레드 풀 스레드에서 개체의 속성을 설정하려고 시도합니다. CLR은 호출을 마샬링할 수 없으며, 개체가 생성된 스레딩 컨텍스트에서만 사용할 수 있음을 나타내는 메시지와 함께 System.InvalidCastException 예외를 던집니다.
Windows.Media.Capture.CameraCaptureUI ccui;
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
ccui = new Windows.Media.Capture.CameraCaptureUI();
await Task.Run(() => {
ccui.PhotoSettings.AllowCropping = true;
});
}
Private ccui As Windows.Media.Capture.CameraCaptureUI
Private Async Sub Button_Click_1(sender As Object, e As RoutedEventArgs)
ccui = New Windows.Media.Capture.CameraCaptureUI()
Await Task.Run(Sub()
ccui.PhotoSettings.AllowCropping = True
End Sub)
End Sub
CameraCaptureUI 설명서에는 "ThreadingAttribute(STA)"가 클래스의 특성으로 나열된 이유 중 하나는, UI 스레드와 같은 단일 스레드 컨텍스트에서 생성되어야 하기 때문입니다.
다른 스레드에서 CameraCaptureUI 개체에 액세스하려는 경우 UI 스레드에 대한 CoreDispatcher 개체를 캐시하고 나중에 사용하여 해당 스레드에 대한 호출을 디스패치할 수 있습니다. 또는 다음 코드와 같이 페이지와 같은 XAML 개체에서 디스패처를 가져올 수 있습니다.
Windows.Media.Capture.CameraCaptureUI ccui;
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
ccui = new Windows.Media.Capture.CameraCaptureUI();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
() => {
ccui.PhotoSettings.AllowCropping = true;
});
}
Dim ccui As Windows.Media.Capture.CameraCaptureUI
Private Async Sub Button_Click_3(sender As Object, e As RoutedEventArgs)
ccui = New Windows.Media.Capture.CameraCaptureUI()
Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
Sub()
ccui.PhotoSettings.AllowCropping = True
End Sub)
End Sub
C++로 작성된 Windows 런타임 구성 요소의 개체
기본적으로 활성화할 수 있는 구성 요소의 클래스는 Agile입니다. 그러나 C++는 스레딩 모델 및 마샬링 동작에 대한 상당한 제어를 허용합니다. 이 문서의 앞부분에서 설명한 것처럼 CLR은 agile 클래스를 인식하고, 클래스가 agile이 아닐 때 호출을 마샬링하려고 시도하고, 클래스에 마샬링 정보가 없는 경우 System.InvalidCastException 예외를 throw합니다.
UI 스레드에서 실행되고 UI 스레드가 아닌 다른 스레드에서 호출할 때 예외를 throw하는 개체의 경우 UI 스레드의 CoreDispatcher 개체를 사용하여 호출을 디스패치할 수 있습니다.