분류 전체보기 (328)
.NET (111)
S/W tip (35)
etc (63)
DB (34)
HOT item~! (48)
Disign pettens (4)
UX (6)
나의 S/W (2)
개발관련 이슈 (16)
Diary (1)
웹플러스 (1)
calendar
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
tags
archive
link
ColorSwitch 00 01 02
▣  Unity Application Block - .NET/C# - 2011. 6. 14. 20:35

출처 : http://aspdotnet.springnote.com/pages/1853294

Data Access Application Block 개요

Chris Brooks, Graeme Malcolm, Alex Mackman, Edward Jezierski
Microsoft Corporation

요약: Data Access Application Block은 저장 프로시저를 호출하고 SQL Server 데이터베이스에 대한 SQL 텍스트 명령을 발급하는 것을 도와주는 최적화된 데이터 액세스 코드가 포함된 .NET 구성 요소입니다. Data Access Application BlockSqlDataReader, DataSetXmlReader 개체를 반환합니다. 사용자의 .NET 응용 프로그램에서 Data Access Application Block을 빌딩 블록으로 사용하면 사용자 지정 코드를 만들고 테스트하고 유지 관리하는 양을 줄일 수 있습니다. 다운로드에는 전체 C#Visual Basic .NET 소스 코드와 다양한 내용의 설명서가 제공됩니다(15페이지/인쇄 페이지 기준).

소개

.NET 응용 프로그램용 데이터 액세스 코드의 디자인 및 개발에 참여하고 있습니까? 동일한 데이터 액세스 코드를 반복해서 쓰고 있다고 느낀 적이 있습니까? 한 줄에서 저장 프로시저를 호출할 수 있도록 도우미 함수로 데이터 액세스 코드를 래핑한 적이 있습니까? 만약 있다면, Microsoft Data Access Application Block for .NET을 사용하십시오.

Data Access Application BlockMicrosoft SQL Server 데이터베이스 액세스를 위해 성능 및 리소스 관리에 유용한 정보를 캡슐화합니다. 사용자의 .NET 응용 프로그램에서 쉽게 빌딩 블록으로 사용할 수 있습니다. Data Access Application Block을 사용하면 사용자 지정 코드를 만들고 테스트하고 유지 관리하는 양이 줄어듭니다.

특히, Data Access Application Block을 사용하면 다음을 실행하는 데 도움이 됩니다.

  • 저장 프로시저 또는 SQL 텍스트 명령 호출
  • 매개 변수 정보 지정
  • SqlDataReader, DataSet 또는 XmlReader 개체 반환

예를 들어, Data Access Application Block을 참조하는 응용 프로그램에서 저장 프로시저를 호출하고 DataSet을 다음과 같이 한 줄의 코드로 생성할 수 있습니다.

          [Visual Basic]
          
          Dim ds As DataSet = SqlHelper.ExecuteDataset( _
          
                connectionString, _
          
                CommandType.StoredProcedure, _
          
                "getProductsByCategory", _
          
                new SqlParameter("@CategoryID", categoryID))
          
           
          
          [C#]
          
          DataSet ds = SqlHelper.ExecuteDataset( 
          
                connectionString,
          
                CommandType.StoredProcedure,
          
                "getProductsByCategory",
          
                new SqlParameter("@CategoryID", categoryID)); 
          
            
          
            
          

참고 Application Block for .NET 디자인은 성공적인 .NET 응용 프로그램을 검토하여 이루어졌으며, 응용 프로그램을 현재 상태로 또는 사용자에 맞게 사용할 수 있는 소스 코드로 제공됩니다. 이것이 다양한 사용 사례에서 데이터 액세스 동작을 자세히 제어하기 위해 빌드되는 Microsoft ADO.NET 라이브러리가 앞으로 취해야 할 경향은 아닙니다. ADO.NET의 이후 버전에서는 이 시나리오가 다른 모델로 설명될 수 있습니다.

이 개요의 나머지 부분은 다음 절들로 분류됩니다.

Data Access Application Block 포함되는 기능은 무엇입니까?

Data Access Application Block 다운로드 설치

Data Access Application Block 사용

내부 디자인

질문과 대답(FAQ)

사용자 의견 지원

공동 작업자

Data Access Application Block에 포함되는 기능은 무엇입니까?

기능을 테스트하는 데 사용할 수 있는 Data Access Application Block의 소스 코드가 Quick Start 샘플 응용 프로그램과 함께 제공됩니다. Data Access Application Block에는 제공되는 코드에 대한 학습과 작업을 도와주는 다양한 내용의 설명서가 포함되어 있습니다.

Visual Studio .NET 프로젝트

Data Access Application Block에는 일반 시나리오를 테스트하는 데 사용할 수 있는 각 언어로 된 Quick Start Samples 클라이언트 응용 프로그램 및 Microsoft Visual Basic .NETMicrosoft Visual C# 소스 코드가 제공됩니다. 이 소스 코드는 Data Access Application Block의 작동 방법을 이해하는 데 도움이 됩니다. 또한, 개별 요구 사항에 따라 소스 코드를 사용자에 맞게 설정할 수 있습니다.

Visual BasicC# Microsoft.ApplicationBlocks.Data 프로젝트를 각각 컴파일하여 Microsoft.ApplicationBlocks.Data.dll이라는 어셈블리를 생성할 수 있습니다. 이 어셈블리에는 데이터베이스 명령 실행을 위한 핵심 기능이 있는 SqlHelper 클래스와 매개 변수 검색 및 캐싱 기능을 제공하는 SqlhelperParameterCache라는 두 번째 클래스가 포함되어 있습니다.

설명서

Data Access Application Block의 설명서는 다음과 같은 절로 구성되어 있습니다.

  • Data Access Application Block을 사용하여 응용 프로그램 개발. 이 절에서는 Data Access Application Block을 빠르고 쉽게 사용할 수 있도록 도와주는 다양한 일반 사용 사례를 다루며 빠른 시작 예제가 나와 있습니다.
  • Data Access Application Block의 디자인 및 구현. 이 절에서는 Data Access Application Block의 디자인과 구현에 대한 통찰력을 제공하는 배경 디자인에 대한 정보를 다룹니다.
  • 배포 및 작업. 이 절에서는 보안 관련 정보와 배포 및 업데이트 옵션을 포함하는 설치 정보를 다룹니다.
  • 참조. 이 절은 Data Access Application Block을 구성하는 클래스와 인터페이스를 자세히 설명하는 광범위한 API 참조 절입니다.

시스템 요구 사항

Data Access Application Block을 실행하려면 다음이 필요합니다.

Data Access Application Block 다운로드 및 설치

서명된 Data Access Application Block 어셈블리 및 다양한 내용의 설명서가 들어 있는 Windows Installer 파일을 사용할 수 있습니다.

설치 프로세스에서는 프로그램 메뉴에 Microsoft Application Blocks for .NET 하위 메뉴를 만듭니다. Microsoft Application Blocks for .NET 하위 메뉴에는 설명서와 Data Access Application Block Visual Studio .NET 솔루션을 시작하는 옵션이 포함되어 있는 데이터 액세스 하위 메뉴가 있습니다.

MSDN Downloads 로 이동하여 다운로드를 엽니다.

Data Access Application Block 사용

이 절에서는 Data Access Application Block을 사용하여 데이터베이스 명령을 실행하고 매개 변수를 관리하는 방법을 설명합니다. 그림 1에서는 Data Access Application Block의 주요 요소를 보여줍니다.

그림 1. Data Access Application Block

SqlHelper 클래스는 SQL Server 데이터베이스에 대해 서로 다른 유형의 다양한 명령을 실행할 수 있는 정적 메서드 집합을 제공합니다.

SqlHelperParameterCache 클래스는 성능을 향상시키는 데 사용되는 명령 매개 변수 캐싱 기능을 제공합니다. 이 클래스는 많은 Execute 메서드(특히, 저장 프로시저만 실행하도록 디자인되는 재정의)에서 내부적으로 사용됩니다. 또한, 데이터 액세스 클라이언트에서 특정 명령에 대해 특정 매개 변수 집합을 캐싱할 때 직접 사용할 수 있습니다.

SqlHelper 클래스를 사용하여 명령 실행

SqlHelper 클래스는 ExecuteNonQuery, ExecuteDataset, ExecuteReader, ExecuteScalar, ExecuteXmlReader의 다섯 가지 공유(Visual Basic) 또는 정적(C#) 메서드를 제공합니다. 구현되는 각 메서드는 일관성 있는 오버로드 집합을 제공합니다. 또한 개발자가 데이터에 액세스하는 데 필요한 수준의 융통성을 제공하는 반면 SqlHelper 클래스를 사용하여 명령을 실행하기 위해 잘 정의된 패턴을 제공합니다. 각 메서드에 제공되는 오버로드는 서로 다른 메서드 인수를 지원하므로, 개발자는 연결, 트랜잭션 및 매개 변수 정보를 전달하는 방법을 결정할 수 있습니다. 이 클래스에서 구현되는 모든 메서드는 다음 오버로드를 지원합니다.

          [Visual Basic]
          
          Execute* (ByVal connection As SqlConnection, _
          
                    ByVal commandType As CommandType, _
          
                    ByVal CommandText As String)
          
           
          
          Execute* (ByVal connection As SqlConnection, _
          
                    ByVal commandType As CommandType, _
          
                    ByVal commandText As String, _
          
                    ByVal ParamArray commandParameters() As SqlParameter)
          
           
          
          Execute* (ByVal connection As SqlConnection, _
          
                    ByVal spName As String, _
          
                    ByVal ParamArray parameterValues() As Object)
          
           
          
          Execute* (ByVal transaction As SqlTransaction, _
          
                    ByVal commandType As CommandType, _
          
                    ByVal commandText As String)
          
           
          
          Execute* (ByVal transaction As SqlTransaction, _
          
                    ByVal commandType As CommandType, _
          
                    ByVal commandText As String, _
          
                    ByVal ParamArray commandParameters() As SqlParameter)
          
           
          
          Execute* (ByVal transaction As SqlTransaction, _
          
                    ByVal spName As String, _
          
                    ByVal ParamArray parameterValues() As Object)
          
           
          
          [C#]
          
          Execute* (SqlConnection connection, CommandType commandType, 
          
                    string commandText)
          
           
          
          Execute* (SqlConnection connection, CommandType commandType,
          
                    string commandText, params SqlParameter[] commandParameters)
          
           
          
          Execute* (SqlConnection connection, string spName, 
          
                    params object[] parameterValues)
          
           
          
          Execute* (SqlConnection connection, 
          
                    CommandType commandType, string commandText)
          
           
          
          Execute* (SqlConnection connection,
          
                    CommandType commandType, string commandText, 
          
                    params SqlParameter[] commandParameters)
          
           
          
          Execute* (SqlConnection connection,
          
                    string spName, params object[] parameterValues)
          

ExecuteXmlReader를 제외한 모든 메서드는 이들 오버로드 외에 다음 메서드 서명에 표시된 것처럼 연결 정보를 연결 개체가 아닌 연결 문자열로 전달할 수 있는 오버로드를 제공합니다.

          [Visual Basic]
          
          Execute* (ByVal connectionString As String, _
          
                    ByVal commandType As CommandType, _
          
                    ByVal commandText As String)
          
           
          
          Execute* (ByVal connectionString As String, _
          
                    ByVal commandType As CommandType, _
          
                    ByVal commandText As String, _
          
                    ByVal ParamArray commandParameters() As SqlParameter)
          
           
          
          Execute* (ByVal connectionString As String, _
          
                    ByVal spName As String, _
          
                    ByVal ParamArray parameterValues() As Object)
          
           
          
          [C#]
          
          Execute* (string connectionString, CommandType commandType, 
          
                    string commandText)
          
           
          
          Execute* (string connectionString, CommandType commandType, 
          
                    string commandText, 
          
                    params SqlParameter[] commandParameters)
          
           
          
          Execute* (string connectionString, string spName, 
          
                    params object[] parameterValues)
          

참고 SqlDataReader 개체와 달리 XmlReader 개체는 XmlReader가 닫힐 때 연결을 자동으로 닫을 수 없기 때문에 ExecuteXmlReader는 연결 문자열을 지원하지 않습니다. 연결 문자열을 전달한 클라이언트에서는 작업을 마칠 때 XmlReader와 관련된 연결 개체를 닫을 수 없습니다.

Data Access Application Block 어셈블리를 참조하고 다음 코드 샘플에 설명된 것처럼 Microsoft.ApplicationBlocks.Data 네임스페이스를 가져와서 SqlHelper 클래스 메서드를 사용하는 코드를 작성할 수 있습니다.

          [Visual Basic]
          
          Imports Microsoft.ApplicationBlocks.Data
          
           
          
          [C#]
          
          using Microsoft.ApplicationBlocks.Data;
          
            
          

네임스페이스를 가져온 다음 아래 코드 샘플에 설명된 것처럼 Execute* 메서드를 호출할 수 있습니다.

          [Visual Basic]
          
          Dim ds As DataSet = SqlHelper.ExecuteDataset( _
          
             "SERVER=(local);DATABASE=Northwind;INTEGRATED SECURITY=True;",
          
               _
          
             CommandType.Text, "SELECT * FROM Products")
          
           
          
          [C#]
          
          DataSet ds = SqlHelper.ExecuteDataset( 
          
             "SERVER=DataServer;DATABASE=Northwind;INTEGRATED
          
               SECURITY=sspi;", _
          
             CommandType.Text, "SELECT * FROM Products");
          

SqlHelperParameterCache 클래스를 사용하여 매개 변수 관리

SqlHelperParameterCache 클래스는 매개 변수를 관리하는 데 사용할 수 있는 세 가지 공개 공유 메서드를 제공합니다. 공개 공유 메서드는 다음과 같습니다.

  • CacheParameterSet. 캐시에서 SqlParameters 배열을 저장하는 데 사용됩니다.
  • GetCachedParameterSet. 캐싱된 매개 변수 배열의 복사본을 검색하는 데 사용됩니다.
  • GetSpParameterSet. 데이터베이스에 쿼리한 다음 나중에 쿼리할 때 결과를 캐싱하여 지정된 저장 프로시저에 대한 해당 매개 변수를 검색하는 데 사용되는 오버로드된 메서드입니다.

매개 변수 캐싱 및 검색

SqlParameter 개체 배열은 CacheParameterSet 메서드를 사용하여 캐싱될 수 있습니다. 이 메서드는 연결 문자열과 명령 텍스트를 연결하여 키를 만든 다음 Hashtable에 매개 변수 배열을 저장합니다.

캐시에서 매개 변수를 검색하려면 GetCachedParameterSet 메서드를 사용합니다. 이 메서드는 캐시에서 이름,, 방향, 데이터 형식 등으로 초기화되고 메서드에 전달되는 연결 문자열과 명령 텍스트에 일치하는 캐시 매개 변수의 SqlParameter 개체 배열을 반환합니다.

참고 매개 변수 집합의 키로 사용되는 연결 문자열은 간단한 문자열 비교를 사용하여 일치됩니다. GetCachedParameterSet에서 매개 변수를 검색하는 데 사용되는 연결 문자열은 CacheParameterSet을 사용하여 해당 매개 변수를 저장하는 데 사용되는 연결 문자열과 완전히 동일해야 합니다. 의미가 동일하더라도 구문이 다른 연결 문자열은 서로 다른 결과를 반환합니다.

다음 코드는 Transact-SQL 문에 대한 매개 변수를 캐싱하여 SqlHelperParameterCache 클래스를 사용하여 검색하는 방법을 보여줍니다.

          [Visual Basic]
          
          '연결 문자열 및 명령 텍스트를 초기화합니다.
          
          '매개 변수를 저장하고 검색하는 데 사용되는 키가 형성됩니다.
          
          Const CONN_STRING As String = _
          
            "SERVER=(local); DATABASE=Northwind; INTEGRATED SECURITY=True;"
          
          Dim sql As String = _
          
                 "SELECT ProductName FROM Products " + _
          
                 "WHERE Category=@Cat AND SupplierID = @Sup"
          
           
          
          '매개 변수를 캐싱합니다.
          
          Dim paramsToStore(1) As SqlParameter
          
          paramsToStore(0) = New SqlParameter("@Cat", SqlDbType.Int)
          
          paramsToStore(1) = New SqlParameter("@Sup", SqlDbType.Int)
          
          SqlHelperParameterCache.CacheParameterSet(CONN_STRING, _
          
                                                    sql, _
          
                                                    paramsToStore)
          
           
          
          '캐시에서 매개 변수를 검색합니다.
          
          Dim storedParams(1) As SqlParameter
          
          storedParams = SqlHelperParameterCache.GetCachedParameterSet( _
          
                                                           CONN_STRING, sql)
          
          storedParams(0).Value = 2
          
          storedParams(1).Value = 3
          
           
          
          '명령에 매개 변수를 사용합니다.
          
          Dim ds As DataSet
          
          ds = SqlHelper.ExecuteDataset(CONN_STRING, _
          
                                        CommandType.Text, _
          
                                        sql, storedParams)
          
           
          
          [C#]
          
          // 연결 문자열 및 명령 텍스트를 초기화합니다.
          
          // 매개 변수를 저장하고 검색하는 데 사용되는 키가 형성됩니다.
          
          const string CONN_STRING =
          
            "SERVER=(local); DATABASE=Northwind; INTEGRATED SECURITY=True;";
          
          string spName = "SELECT ProductName FROM Products " + 
          
                          "WHERE Category=@Cat AND SupplierID = @Sup";
          
           
          
          //매개 변수를 캐싱합니다.
          
          SqlParameter[] paramsToStore = new SqlParameter[2];
          
          paramsToStore[0] = New SqlParameter("@Cat", SqlDbType.Int);
          
          paramsToStore[1] = New SqlParameter("@Sup", SqlDbType.Int);
          
          SqlHelperParameterCache.CacheParameterSet(CONN_STRING, 
          
                                                    sql, 
          
                                                    paramsToStore);
          
           
          
          //캐시에서 매개 변수를 검색합니다.
          
          SqlParameter storedParams = new SqlParameter[2];
          
          storedParams = SqlHelperParameterCache.GetCachedParameterSet(
          
                                                        CONN_STRING, sql);
          
          storedParams(0).Value = 2;
          
          storedParams(1).Value = 3;
          
           
          
          //명령에 매개 변수를 사용합니다.
          
          DataSet ds;
          
          ds = SqlHelper.ExecuteDataset(CONN_STRING, 
          
                                        CommandType.StoredProcedure,
          
                                        sql, storedParams);
          

저장 프로시저 매개 변수 검색

또한 SqlHelperParameterCache는 특정 저장 프로시저에 대한 매개 변수 배열을 검색하는 방법을 제공합니다. 두 구현이 있는 GetSpParameterSet라는 오버로드된 메서드가 이 기능을 제공합니다. 이 메서드는 캐시에서 지정된 저장 프로시저에 대한 매개 변수를 검색하려고 시도합니다. 매개 변수가 캐싱되지 않으면 .NET SqlCommandBuilder 클래스를 사용하여 내부적으로 검색한 다음 후속 요청이 있을 때 캐시에 추가합니다. 그런 다음 매개 변수가 클라이언트 배열에 반환되기 전에 해당 매개 변수 설정을 각 매개 변수에 할당합니다. 다음 코드는 Northwind 데이터베이스에서 SalesByCategory 저장 프로시저에 대한 매개 변수를 검색하는 방법을 보여줍니다.

          [Visual Basic]
          
          '연결 문자열 및 명령 텍스트를 초기화합니다.
          
          '매개 변수를 저장하고 검색하는 데 사용되는 키가 형성됩니다.
          
          Const CONN_STRING As String = _
          
            "SERVER=(local); DATABASE=Northwind; INTEGRATED SECURITY=True;"
          
          Dim spName As String = "SalesByCategory"
          
           
          
          '매개 변수를 검색합니다.
          
          Dim storedParams(1) As SqlParameter
          
          storedParams = SqlHelperParameterCache.GetSpParameterSet( _
          
                                                    CONN_STRING, spName)
          
          storedParams(0).Value = "Beverages"
          
          storedParams(1).Value = "1997"
          
           
          
          '명령에 매개 변수를 사용합니다.
          
          Dim ds As DataSet
          
          ds = SqlHelper.ExecuteDataset(CONN_STRING, _
          
                                        CommandType.StoredProcedure, _
          
                                        spName, storedParams)
          
           
          
          [C#]
          
          // 연결 문자열 및 명령 텍스트를 초기화합니다.
          
          / 매개 변수를 저장하고 검색하는 데 사용되는 키가 형성됩니다.
          
          const string CONN_STRING = 
          
            "SERVER=(local); DATABASE=Northwind; INTEGRATED SECURITY=True;";
          
          string spName = "SalesByCategory";
          
           
          
          // 매개 변수를 검색합니다.
          
          SqlParameter storedParams = new SqlParameter[2];
          
          storedParams = SqlHelperParameterCache.GetSpParameterSet(
          
                                                    CONN_STRING, spName);
          
          storedParams[0].Value = "Beverages";
          
          storedParams[1].Value = "1997";
          
           
          
          //명령에 매개 변수를 사용합니다.
          
          DataSet ds;
          
          ds = SqlHelper.ExecuteDataset(CONN_STRING, 
          
                                        CommandType.StoredProcedure,
          
                                        spName, storedParams);
          

내부 디자인

Data Access Application Block에는 전체 소스 코드와 디자인에 대한 자세한 가이드가 포함되어 있습니다. 이 절에서는 주요 구현 정보를 설명합니다.

SqlHelper 클래스 구현 정보

SqlHelper 클래스는 정적 메서드 집합을 통해 데이터 액세스 기능을 캡슐화하기 위한 것입니다. 이 클래스는 상속되거나 인스턴스화될 수 없기 때문에 개인 생성자를 사용하여 상속 불가능 클래스로 선언됩니다.

SqlHelper 클래스에서 구현되는 각 메서드는 일관성 있는 오버로드 집합을 제공합니다. 또한 개발자가 데이터에 액세스하는 데 필요한 수준의 융통성을 제공하는 반면 SqlHelper 클래스를 사용하여 명령을 실행하기 위해 잘 정의된 패턴을 제공합니다. 각 메서드에 제공되는 오버로드는 서로 다른 메서드 인수를 지원하므로, 개발자는 연결, 트랜잭션 및 매개 변수 정보를 전달하는 방법을 결정할 수 있습니다. SqlHelper 클래스에서 구현되는 메서드는 다음과 같습니다.

  • ExecuteNonQuery. 이 메서드는 행이나 값을 반환하지 않는 명령을 실행하는 데 사용됩니다. 일반적으로 데이터베이스 업데이트를 실행하는 데 사용되지만, 저장 프로시저에서 출력 매개 변수를 반환하는 데에도 사용될 수 있습니다.
  • ExecuteReader. 이 메서드는 명령에 의해 반환되는 결과 집합이 들어 있는 SqlDataReader 개체를 반환하는 데 사용됩니다.
  • ExecuteDataset. 이 메서드는 명령에 의해 반환되는 결과 집합이 들어 있는 DataSet 개체를 반환합니다.
  • ExecuteScalar. 이 메서드는 단일 값을 반환합니다. 이 값은 항상 명령에 의해 반환되는 첫 번째 행의 첫째 열입니다.
  • ExecuteXmlReader. 이 메서드는 FOR XML 쿼리에서 XML 조각을 반환합니다.

SqlHelper 클래스에는 공개 메서드 외에도 매개 변수를 관리하고 명령 실행을 준비하는 데 사용되는 많은 개인 함수가 포함되어 있습니다. 클라이언트가 호출하는 메서드 구현에 관계없이 모든 명령은 SqlCommand 개체를 사용하여 실행됩니다.SqlCommand 개체가 실행되기 전에 매개 변수 컬렉션에 모든 매개 변수를 추가한 다음 Connection, CommandType, CommandTextTransaction 속성을 올바르게 설정해야 합니다. SqlHelper 클래스의 개인 함수는 클라이언트 응용 프로그램이 호출하는 오버로드된 메서드 구현에 관계없이 주로 SQL Server 데이터베이스에 대한 명령을 일관성 있게 실행할 수 있는 수단을 제공하기 위한 것입니다. SqlHelper 클래스의 개인 유틸리티 함수는 다음과 같습니다.

  • AttachParameters: 실행 중인 SqlCommand에 필요한 SqlParameter 개체를 첨부하는 데 사용되는 함수
  • AssignParameterValues: SqlParameter 개체에 값을 할당하는 데 사용되는 함수
  • PrepareCommand: 연결, 트랜잭션 컨텍스트 등과 같은 명령 속성을 초기화하는 데 사용되는 함수
  • ExecuteReader: ExecuteReader의 이 개인 구현은 읽기 프로그램과 가장 효과적으로 연관되는 연결 수명을 관리하기 위해 해당 CommandBehavior를 사용하여 SqlDataReader 개체를 여는 데 사용됩니다.

SqlHelperParameterCache 클래스 구현 정보

매개 변수 배열이 개인 Hashtable에 캐싱됩니다. 캐싱된 매개 변수 배열에 영향을 미치지 않고 클라이언트 응용 프로그램에서 매개 변수 값 등을 변경할 수 있도록 캐시에서 검색된 매개 변수를 복사합니다. 이 목적을 위해 CloneParameters라는 개인 공유 함수를 사용합니다.

질문과 대답(FAQ)

이 릴리스의 새로운 기능은 무엇입니까?

Data Access Application BlockRTM 릴리스에는 다음과 같은 새로운 기능 및 베타 2.0 릴리스에서 변경된 기능이 포함되어 있습니다.

  • SqlHelper 클래스 메서드의 트랜잭션 오버로드에 더 이상 SqlConnection 매개 변수가 필요하지 않습니다. 이번 릴리스에서는 연결 정보가 SqlTransaction 개체에서 파생되기 때문에 메서드 서명에 SqlConnection 개체 매개 변수를 포함시킬 필요가 없습니다.
  • GetSpParameterSet 메서드는 ADO.NET CommandBuilder 클래스의 DeriveParameters 메서드를 사용하여 저장 프로시저에 필요한 매개 변수를 확인합니다. 이 기능은 데이터베이스에 직접 쿼리하여 정보를 검색하는 베타 2.0 릴리스에 사용된 기술보다 더욱 효과적입니다.

XCOPY 배포를 사용하여 Data Access Application Block 어셈블리를 배포할 수 있습니까?

. 컴파일한 후 Microsoft,ApplicationBlocks.Data.dll 어셈블리가 XCOPY를 배포할 수 있습니다.

ExecuteDataset 메서드를 사용해야 하는 시기와 ExecuteReader 메서드를 사용해야 하는 시기는 언제입니까?

실제 질문은 DataSet 개체에 여러 데이터 행을 반환해야 하는 시기와 DataReader를 사용해야 하는 시기입니다. 대답은 원시 성능과 비교하여 융통성 면에서의 우선 순위와 특정 응용 프로그램의 필요성에 따라 달라집니다. DataSets는 데이터에 대한 융통성 있고 연결이 끊긴 관계형 보기를 제공하고, DataReaders는 매우 높은 성능의 읽기 전용 전방형 커서만 제공합니다. DataSetsDataReaders에 대한 자세한 비교는 Data Access Architecture Guide 를 참조하십시오.

ExecuteDataset을 사용하여 여러 테이블이 있는 DataSet을 반환하는 방법은 무엇입니까?

(여러 SELECT 문을 실행하거나 다른 저장 프로시저를 중첩 호출하여) 여러 행 집합을 반환하는 저장 프로시저를 만들고 ExecuteDataset 메서드로 해당 프로시저를 실행하여 여러 테이블이 들어 있는 DataSet을 검색할 수 있습니다.

예를 들어, 데이터베이스에 다음과 같은 저장 프로시저가 있다고 가정합니다.

          CREATE PROCEDURE GetCategories
          
          AS
          
          SELECT * FROM Categories
          
          GO
          
          CREATE PROCEDURE GetProducts
          
          AS
          
          SELECT * FROM Products
          
            
          

다음 코드 샘플에 설명된 것처럼 이들 프로시저를 중첩 호출하는 마스터 저장 프로시저를 만들 수 있습니다.

          CREATE PROCEDURE GetCategoriesAndProducts
          
          AS
          
          BEGIN
          
            EXEC GetCategories
          
            EXEC GetProducts
          
          END
          
            
          

ExecuteDataset 메서드를 사용하여 이 마스터 저장 프로시저를 실행하면 각각 카테고리 데이터와 제품 데이터가 들어 있는 두 테이블이 포함된 하나의 DataSet이 반환됩니다.

참고 ExecuteDataset 메서드에서는 반환되는 테이블에 사용자에 맞게 설정할 수 있는 이름을 할당할 수 없습니다. 첫 번째 테이블은 항상 번호가 0이고 이름이 Table입니다. 두 번째 테이블은 번호가 1이고 이름이 Table1입니다. 테이블의 이름과 번호는 항상 이런 식으로 지정됩니다.

다른 응용 프로그램 블록이 있습니까?

Data Access Application Block은 현재 릴리스되어 있는 여러 Application Blocks 중 하나입니다. 이러한 Application Block은 개발자가 프로젝트에서 직면하는 일반적인 문제들을 해결합니다. Application Block.NET 응용 프로그램에 빠르고 쉽게 연결됩니다.

사용자 의견 및 지원

질문? 설명? 제안? Data Access Application Block에 대한 사용자 의견은 devfdbck@microsoft.com으로 보내주십시오.

Application Blocks for .NET.NET 분산 응용 프로그램 개발 입문자용으로, 샘플 코드와 설명서를 "있는 그대로" 제공합니다. Application Blocks for .NET은 테스트를 거쳐 강력한 코드 집합으로 간주되나, 전통적인 Microsoft 제품처럼 지원되지는 않습니다.

또한 이 프로그램 사용자를 지원하기 위해 뉴스 그룹이 만들어졌습니다. 온라인 열린 포럼을 통해 동료 및 Microsoft Support Professionals과 논의하려면 이 뉴스 그룹을 사용하십시오.

그 밖의 모든 사람들에게는 질문과 설명을 통해 도움을 주며, 본사의 개발팀에서 뉴스 그룹을 매일 모니터링합니다.
뉴스 그룹: 웹 기반 독자
http://msdn.microsoft.com/newsgroups/loadframes.asp?icp=msdn&slcid=us&newsgroup=microsoft.public.dotnet.distributed_apps

뉴스 그룹: NNTP 독자
news://msnews.microsoft.com/microsoft.public.dotnet.distributed_apps

.NET의 강력한 기능을 배우고 이용하시겠습니까? Microsoft Technology Centers의 엔지니어와 함께 작업하여 개발의 유용한 정보를 학습하십시오. 자세한 내용을 보려면 http://www.microsoft.com/business/services/mtc.asp 를 방문하십시오.

추가로 도움말이 필요하십니까? 간단한 컨설팅을 위한 혁신적인 솔루션인 Advisory Services 지원에 대한 최신 추가된 도움말을 확인해 보십시오. Advisory Services에 대한 자세한 내용을 보려면 http://support.microsoft.com/default.aspx?scid=FH;EN-US;offer58&FR=0&SD=GN&LN=EN-US&CT=SD&SE=NONA 를 참조하십시오.

추가 정보

Data Access Application BlockData Access in .NET Architecture Guide 에서 자세히 설명된 유용한 정보 및 일반 디자인 원칙을 기반으로 디자인되고 개발됩니다. 데이터 액세스에 대한 자세한 내용은 이 가이드를 참조하십시오.

공동 작업자

기고 및 검토를 도와준 Susan Warren, Brad Abrams, Andy Dunn, Michael Day, Mark Ashton, Gregory Leake, Steve Busby, Kenny Jones, David Schleifer, Andrew Roubin(Vorsite Corp.), Jeffrey Richter(Wintellect), Bernard Chen(Sapient)Matt Drucker(Turner Broadcasting)에게 깊은 감사를 드립니다.

또한, 컨텐트팀의 Tina Burden(Entirenet), Shylender Ramamurthy(Infosys Technologies Ltd)Filiberto Selvas Patino에게도 감사를 드립니다.

 

▣  C# 3.0 개요 - .NET/C# - 2011. 6. 14. 20:32
출처 : http://hsj0511.tistory.com/entry/C-30-개요

/C# / 2009/09/11 16:17

C# 3.0 개요

Anders Hejlsberg, Mads Torgersen
March 2007

적용 대상 :
Visual C# 3.0
개요 : C# 3.0 기술 개요입니다.높은 순서로 함수 스타일의 클래스 라이브러리 작성과 사용을 지원하는 C# 2.0 기반의 언어확장을 소개합니다.

목차

소개
26.1 암시적으로 형식화된 로컬 변수
26.2 확장 메서드
26.2.1 확장 메서드 선언
26.2.2 사용 가능한 확장 메서드
26.2.3 확장 메서드 호출
26.3 lambda 식
26.3.1 익명 메서드와 lambda 식변환
26.3.2 대리자(delegate) 작성식
26.3.3 형식 유추
26.3.3.1 제 1 단계
26.3.3.2 제 2 단계
26.3.3.3 입력 형식
26.3.3.4 출력 형식
26.3.3.5 종속성
26.3.3.6 출력 형식 유추
26.3.3.7 명시적 인수 형식 유추
26.3.3.8 정확한 유추
26.3.3.9 낮은 바인딩 유추
26.3.3.10 고정
26.3.3.11 유추되는 반환 형식
26.3.3.12 메서드 그룹의 변환 형식 유추
26.3.3.13 식직합의 최적 공통 형식
26.3.4 오버로드 해결
26.4 개체 이니셜라이저와 컬렉션 이니셜라이저
26.4.1. 개체 이니셜라이저
26.4.2 컬렉션 이니셜라이저
26.5 익명형식
26.6 암시적으로 형식화된 배열
26.7 쿼리 식
26.7.1 쿼리 식 변환
26.7.1.1 연속된 select 절과 groupby 절
26.7.1.2 범위 변수의 명시적 형식
26.7.1.3 역쿼리식
26.7.1.4 from 절, let 절, where 절, join 절, orderby 절
26.7.1.5 select 절
26.7.1.6 groupby 절
26.7.1.7 투명한 식별자(dentifiers)
26.7.2 쿼리 식 패턴
26.8 식 트리
26.8.1 오버로드 해결
26.9 자동적으로 구현된 속성

소개

이 기사에는 Visual C# 3.0에 적용된 몇가지 업데이트 내용이 포함되어 있습니다. 종합적인 사양은 언어 출시 때에는 제공될 예정입니다.
C# 3.0 에서는 높은 순서의 함수 스타일의 클래스 라이브러리 작성과 사용을 지원하는 C# 2.0 을 기반으로 몇가지의 언어 확장이 도입되었습니다. 이러한 언어 확장으로 관계형 데이터베이스나 XML 등의 분야의 쿼리 언어와 동등의 표현력을 가지는 합성 API 구축이 가능합니다. 확장 기능은 다음과 같습니다.
  • 암시적으로 형식화된 로컬 변수 : 로컬 변수 초기화에 사용되는 식에서 로컬 변수의 형식을 유추할 수 있습니다.
  • 확장 메서드 : 기존의 형식이나 구축된 형식을 추가 메서드로 확장할 수 있습니다.
  • lambda 식: 익명 메서드 진화형으로, 고도의 형식 유추 및 대리자(delegate) 형식이나 식트리 변환을 제공합니다.
  • 개체 이니셜라이저:  개체 구축과 초기화가 간단합니다.
  • 익명형식 : 개체 이니셜라이저에서 자동적으로 유추되어 작성되는 튜플형입니다.
  • 암시적으로 형식화된 배열 : 배열 이니셜라이저에서 배열의 요소 형식을 유추하는 배열 작성과 초기화 형식입니다.
  • 쿼리 식 :  SQL 나 XQuery 등의 관계형 쿼리 언어 및 계층 쿼리 언어를 닮은 언어에 통합된 쿼리 용무의 구문을 제공합니다.
  • 식 트리 :  lambda 식을 코드 (대리자(delegate) 형식)가 아닌 데이터 (식 트리)로서 표현할 수 있습니다.
이 기사에서는 이러한 기능의 기술 개요를 제공합니다. 이 기사에서는「C# 언어 사양 Version 1.2」(§1 ~ §18)과 「C# 버전 2.0 사양」(§19 ~ §25)를 다루며, Visual Studio 2005 설치 디렉터리 다음과 같은 "VC#\Specifications\1041\" 디렉터리에서 이용 가능합니다.

26.1 암시적으로 형식화된 로컬 변수

암시적으로 형식화된 로컬 변수 선언에서는 선언된 로컬 변수의 형식은 그 변수 초기화에 사용되는 식에서 유추됩니다.로컬 변수 선언으로 형식으로서 var 를 지정하고 , var 라는 이름 형식이 범위 안에 없는 경우, 그 선언은 암시적으로 형식화된 로컬 변수 선언입니다.다음은 예를 나타냅니다.
var i = 5;
 var s = "Hello";
var d = 1.0;
var numbers = new int[] {1, 2, 3};
var orders = new Dictionary<int,Order>();
상기의 암시적으로 형식화된 로컬 변수 선언은 다음에 나타나는 명시적으로 형식화된 선언과 완전히 동등합니다.
int i = 5;
string s = "Hello";
double d = 1.0;
int[] numbers = new int[] {1, 2, 3};
Dictionary<int,Order> orders = new Dictionary<int,Order>();
암시적으로 형식화된 로컬 변수 선언의 로컬 변수 선언자에게는 다음과 같은 제한이 있습니다.
  • 선언자에게 이니셜라이저가 포함되어있어야 합니다.
  • 이니셜라이저는 식이어야 합니다.
  • 이니셜라이저식에는 컴파일시 형식을 지정할 필요가 있어, 이 형식은 null 형 이외의 형식이어야 합니다.
  • 로컬 변수 선언에 복수의 선언자를 포함할 수 없습니다.
  • 선언한 변수 자체를 이니셜라이저로 참조할 수 없습니다.
암시적으로 형식화된 로컬 변수 선언이 잘못된 예입니다.
var x;               // 오류.형식 유추에 사용하는 이니셜라이저가 없다.
var y = {1, 2, 3};   // 오류.컬렉션 이니셜라이저는 허가되지 않다.
var z = null;        // 오류.null 형은 허가되지 않다.
var u = x => x + 1;  // 오류.lambda 식으로 형식이 지정되지 않다.
var v = v++;         // 오류.변수 자체를 이니셜라이저로 참조할 수 없다.
로컬 변수 선언으로 형식으로서 var 를 지정해, var 라는 이름 형식이 범위 안에 있는 경우, 하위 호환성의 이유에서 그 선언은 그 형식을 참조합니다.다만, var 라는 이름 형식은 "형식 이름은 대문자로 시작한다" 는  규약에 위반하므로, 이러한 상황이 발생할 일은 거의 없을 것입니다.
for 구문 (§8.8.3)의 for-initializer 및 using 구문 (§8.13)의 resource-acquisition은 암시적으로 형식화된 로컬 변수 선언으로 할 수 있습니다. foreach 구문 (§8.8.4)의 반복 변수는 암시적으로 형식화된 로컬 변수로서 선언할 수 있습니다.이 경우, 반복 변수의 형식은 열거된 컬렉션 요소 형식으로 유추됩니다.다음은 예를 나타냅니다.
int[] numbers = { 1, 3, 5, 7, 9 };
foreach (var n in numbers) Console.WriteLine(n);
이 예에서는 n 형식은 numbers 요소 형식인 int 로 유추됩니다.
암시적으로 형식화된 로컬 변수 선언을 포함할 수 있는 것은 local-variable-declaration,for-initializer,resource-acquisition 및 foreach-statement 뿐입니다.

26.2 확장 메서드

확장 메서드는 인스턴스 메서드 구문을 사용하여 호출할 수 있는 정적 메서드입니다. 실질적으로는 확장 메서드를 사용하면, 기존의 형식이나 구축된 형식을 추가 메서드로 확장할 수 있습니다.
   확장 메서드는 인스턴스 메서드에 비해, 찾아내기 어렵고, 기능도 한정되어 있습니다. 이 때문에 확장 메서드 사용은 가능한 한 삼가해 인스턴스 메서드가 적합하지 않는 경우나 사용할 수 없는 경우에게만 사용하는 것을 추천합니다.속성, 이벤트, 연산자 등, 다른 종류의 확장 멤버에 대해서는 검토중이지만, 현재로서는 지원 되지 않습니다.

26.2.1 확장 메서드 선언

확장 메서드는 메서드의 첫번째 매개 변수에 수식자로서 키워드 this 를 지정하여 선언합니다. 확장 메서드는 non-generic 상자로 되지 않은 정적 클래스에서만 선언 가능합니다. 2개의 확장 메서드를 선언하는 정적 클래스의 예입니다.
namespace Acme.Utilities
{
   public static class Extensions
   {
      public static int ToInt32(this string s) {
         return Int32.Parse(s);
      }
      public static T[] Slice<T>(this T[] source, int index, int count) {
         if (index < 0 || count < 0 || source.Length ? index < count)
            throw new ArgumentException();
         T[] result = new T[count];
         Array.Copy(source, index, result, 0, count);
         return result;
      }
   }
}
확장 메서드의 첫번째의 매개 변수에는 this 이외의 수식자를 지정할 수 없습니다.또, 이 매개 변수의 형식을 포인터형으로 할 수 없습니다.
확장 메서드에는 일반적인 정적 메서드 기능이 모두 갖춰지고 있습니다.또, 확장 메서드는 가져오기 하면, 인스턴스 메서드 구문을 사용하여 호출할 수 있습니다.

26.2.2 사용 가능한 확장 메서드

확장 메서드는 정적 클래스내에서 선언하는지, 네임 스페이스 안에서 using-namespace-directive (§9.3.2)를 사용하여 가져오기 하면, 네임 스페이스 안에서 사용할 수 있습니다. 따라서, using-namespace-directive를 사용하면, 가져오기 한 네임 스페이스에 포함되는 형식이 가져오기 될 뿐만 아니라, 가져오기 한 네임 스페이스 안의 모든 정적 클래스의 모든 확장 메서드가 가져오기 됩니다.
실질적으로는 사용 가능한 확장 메서드는 첫번째의 매개 변수로 지정한 형식의 추가 메서드로서 다루어져 일반적인 인스턴스 메서드보다 우선도는 낮아집니다.예를 들어, 다음과 같이 using-namespace-directive를 사용하여 위의 예의 Acme.Utilities 네임 스페이스를 가져오기 했다고 합니다.
using Acme.Utilities;
이 경우, 다음과 같이 인스턴스 메서드 구문을 사용하여 정적 클래스 Extensions 내의 확장 메서드를 호출하는 것이 가능합니다.
string s = "1234";
int i = s.ToInt32();               // Extensions.ToInt32(s)와 같다
int[] digits = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] a = digits.Slice(4, 3);      // Extensions.Slice(digits, 4, 3)과 같다

26.2.3 확장 메서드 호출

여기에서는 확장 메서드 호출에 관한 상세한 규칙에 대해 설명합니다.다음에 나타나는 형식 메서드 호출 (§7.5.5.1)
expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )
의 각각에서는 일반적인 호출 처리에 의해 적절한 인스턴스 메서드가 검색 되지 않았던 경우 (구체적으로는 호출 후보가 되는 메서드 그룹가 비어 있는 경우), 구문을 확장 메서드 호출로 처리하도록 시도됩니다.우선, 메서드 호출은 각각 다음과 같은 한쪽에 고쳐 쓸 수 있습니다.
identifier ( expr )
identifier ( expr , args )
identifier < typeargs > ( expr )
identifier < typeargs > ( expr , args )
지속적으로 고쳐 쓸 수 있었던 형식은 identifier 해결 방법 이외는 정적 메서드 호출로 처리됩니다. identifier가 지정된 이름을 가지는 네임 스페이스 안의 사용 가능하고 접근 가능한 모든 확장 메서드로 구성되는 메서드 그룹에 대해서, 고쳐 쓸 수 있었던 메서드 호출의 연속된처리가 시도됩니다.이것은 외부을 둘러싸는 가장 가까운 네임 스페이스 선언에서 시작되어, 외부을 둘러싸는 각 네임 스페이스 선언으로 계속되고 그것을 포함한 컴파일 유닛으로 끝납니다.이 세트에서 적절하지 않은 메서드 (§7.4.2.1) 및 첫번째의 인수에서 첫번째의 매개 변수에의 암시적인, ID 변환, 참조의 변환 또는 박스화 변환이 존재하지 않는 메서드를 모두 제외합니다.이러한 후보 메서드, 비어 있지 않은 세트를 가져오는 최초의 메서드 그룹이 고쳐 쓸 수 있었던 메서드 호출용으로 선택되는 그룹이며, 최적인 확장 메서드를 후보세트에서 선택하기 위해 일반적인 오버로드 해결 (§7.4.2)이 적용됩니다.모든 시도가 완료해도 후보 메서드 그룹가 비어 있는 경우는 컴파일시 오류가 발생합니다.
상기의 규칙은 인스턴스 메서드가 확장 메서드보다 우선되어 안쪽의 네임 스페이스 선언으로 사용 가능한 확장 메서드가 외부의 네임 스페이스 선언으로 사용 가능한 확장 메서드보다 우선되는 것을 의미합니다.예입니다.
public static class E
{
   public static void F(this object obj, int i) { }
   public static void F(this object obj, string s) { }
}
class A { }
class B
{
   public void F(int i) { }
}
class C
{
   public void F(object obj) { }
}
class X
{
   static void Test(A a, B b, C c) {
      a.F(1);            // E.F(object, int)
      a.F("hello");      // E.F(object, string)
      b.F(1);            // B.F(int)
      b.F("hello");      // E.F(object, string)
      c.F(1);            // C.F(object)
      c.F("hello");      // C.F(object)
   }
}
이 예에서는 B 메서드는 첫번째의 확장 메서드보다 우선되어 C 메서드는 어느 쪽의 확장 메서드보다 우선됩니다.

26.3 lambda 식

C# 2.0 으로 도입된 익명 메서드를 사용하면, 대리자(delegate) 값이 예상되는 개소에서 코드 블록을 "인라인(in-line)" 기술할 수 있습니다.익명 메서드를 사용하면, 함수형 프로그램 언어의 표현력이 대부분이 제공되지만 익명 메서드 구문에는 그 구문이 약간 장황하고 명령적입니다. lambda 식을 사용하면, 보다 간결하고 기능적인 구문으로 익명 메서드를 기술할 수 있습니다.
lambda 식은 매개 변수 리스트예  계속 되는 => 토큰 및 거기에 계속 되는 식 또는 구문 블록으로 기술합니다.
expression:
    assignment
    non-assignment-expression
    
non-assignment-expression:
    conditional-expression
    lambda-expression
    query-expression
    
lambda-expression:
    (   lambda-parameter-listopt   )   =>   lambda-expression-body
    implicitly-typed-lambda-parameter   =>   lambda-expression-body
    
lambda-parameter-list:
    explicitly-typed-lambda-parameter-list
    implicitly-typed-lambda-parameter-list
    explicitly-typed-lambda-parameter-list
    explicitly-typed-lambda-parameter
    explicitly-typed-lambda-parameter-list   ,   explicitly-typed-lambda-parameter

explicitly-typed-lambda-parameter:
    parameter-modifieropt   type   identifier
    implicitly-typed-lambda-parameter-list
    implicitly-typed-lambda-parameter
    implicitly-typed-lambda-parameter-list   ,   implicitly-typed-lambda-parameter

implicitly-typed-lambda-parameter:
    identifier
    
lambda-expression-body:
    expression
    block
=> 연산자의 우선 순위는 대입 (=)과 같습니다.또, 이 연산자는 오른쪽 결합입니다.
lambda 식 매개 변수는 명시적으로 형식 지정하는 일도 암시적으로 형식 지정할 수도 있습니다.명시적으로 형식화된 매개 변수 리스트에서는 각 매개 변수의 형식은 명시적으로 지정됩니다.암시적으로 형식화된 매개 변수 리스트에서는 매개 변수의 형식은 lambda 식이 사용되는 문맥에서 유추됩니다.구체적으로는 lambda 식이 호환성이 있는 대리자(delegate) 형식에 변환될 때, 그 대리자(delegate) 형식에 의해 매개 변수의 형식이 제공됩니다 (§26.3.1).
매개 변수가암시적으로 형식화된 것 하나뿐인 lambda 식에서는 매개 변수 리스트의 괄호를 생략 할 수 있습니다.즉,
( param ) => expr
 lambda 식은 다음과 같이 축약할 수 있습니다.
param => expr
lambda 식 예를 다음에 몇가지 보여줍니다.
x => x + 1                     // 암시적인 형식 지정.expression body가 식.
x => { return x + 1; }         // 암시적인 형식 지정.expression body가 구문.
(int x) => x + 1               // 명시적 형식 지정.expression body가 식.
(int x) => { return x + 1; }   // 명시적 형식 지정.expression body가 구문.
(x, y) => x * y               // 복수의 매개 변수.
() => Console.WriteLine()      // 매개 변수 없음.
「C# 버전 2.0 사양」 §21 에 기재되어 있는 익명 메서드 사양은 lambda 식에서도 대부분 적용됩니다.. lambda 식은 다음과 같은 점을 제외하고, 기능적으로는 익명 메서드를 닮아 있습니다.
  • 익명 메서드에서는 매개 변수 리스트를 완전하게 생략하고, 모든 매개 변수 리스트의 대리자(delegate) 형식으로 변환할 수 있도록 가능합니다.
  • lambda 식에서는 매개 변수의 형식을 생략 해 유추시킬 수 있지만, 익명 메서드에서는 매개 변수의 형식을 명시적으로 지정해야 합니다.
  • lambda 식 expression body에는 식도 구문 블록도 지정할 수 있지만, 익명 메서드 expression body로 지정할 수 있는 것은 구문 블록만입니다.
  • expression body가 식의 lambda 식은 식 트리로 변환할 수 있습니다 (§26.8).

26.3.1 익명 메서드와 lambda 식변환

   이 섹션은 §21.3 에 대신합니다.
anonymous-method-expression lambda 식은 특별한 변환 규칙을 가지는 값으로 해서 분류됩니다.이러한 값에는 형식이 없습니다만, 호환성이 있는 대리자(delegate) 형식에 암시적으로 변환 가능합니다.구체적으로는 다음과 같은 조건에 해당하는 경우에 대리자(delegate) 형식 D 는 익명 메서드 또는 lambda 식 L과 호환성이 있습니다.
  • D 와 L 의 매개 변수 수가 같습니다.
  • L 가 anonymous-method-signature를 포함하지 않는 익명 메서드인 경우, D 의 매개 변수가out 매개 변수 수식자가 지정된 매개 변수 이외이면, D 는 0 개 이상의 어떠한 형식의 매개 변수에서도 가질 수 있습니다.
  • L 가 명시적으로 형식화된 매개 변수 리스트를 가지는 경우, D 의 각 매개 변수의 형식 및 수식자는 L 의 대응하는 매개 변수와 같습니다.
  • L 가 암시적으로 형식화된 매개 변수 리스트를 가지는 lambda 식 경우, D 는 ref 매개 변수 또는 out 매개 변수를 가지지 않습니다.
  • D 의 반환 형식이 void 이며, L expression body가 식의 경우, L 의 각 매개 변수에 D 의 대응하는 매개 변수의 형식이 지정되어 있으면, L expression body는 statement-expression (§8.6)으로서 허가된 유효한 식 (§7 참조)입니다.
  • D 의 반환 형식이 void 이며, L expression body가 구문 블록의 경우, L 의 각 매개 변수에 D 의 대응하는 매개 변수의 형식이 지정되어 있으면, L expression body는 return 구문이 식을 지정하고 있지 않는 유효한 구문 블록 (§8.2 참조)입니다.
  • D 의 반환 형식이 void 이외며, L expression body가 식의 경우, L 의 각 매개 변수에 D 의 대응하는 매개 변수의 형식이 지정되어 있으면, L expression body는 D 의 반환 형식에 암시적으로 변환 가능한 유효한 식 (§7 참조)입니다.
  • D 의 반환 형식이 void 이외의, L expression body가 구문 블록의 경우, L 의 각 매개 변수에 D 의 대응하는 매개 변수의 형식이 지정되어 있으면, L expression body는 각 return 구문이 D 의 반환 형식에 암시적으로 변환 가능한 식을 지정하는 도달 불가능한 끝점(endpoint)를 가지는 유효한 구문 블록 (§8.2 참조)입니다.
다음의 예에서는 형식 A 인수를 받아, 형식 R 값을 돌려주는 함수를 나타내는 제네릭 대리자(delegate) 형식 Func<A,R> 를 사용합니다.
delegate R Func<A,R>(A arg);
다음의 대입식
Func<int,int> f1 = x => x + 1;         // OK
Func<int,double> f2 = x => x + 1;      // OK
Func<double,int> f3 = x => x + 1;      // 오류
그럼, 각 lambda 식 매개 변수와 반환 형식은 lambda 식 대입처의 변수의 형식에서 결정됩니다.첫번째의 대입식에서는 lambda 식이 대리자(delegate) 형식 Func<int,int> 에 정상적으로 변환됩니다.x 에 형식 int 가 지정되어 있는 경우, x + 1 은 형식 int 에 암시적으로 변환 가능한 유효한 식이기때문입니다.같이 2 번째의 대입식에서는 lambda 식이 대리자(delegate) 형식 Func<int,double> 에 정상적으로 변환됩니다.이것은 x + 1 의 결과 (형식 int)는 형식 double 에 암시적으로 변환 가능하기 때문에입니다.그러나, 3 번째의 대입식에서는 컴파일시 오류가 됩니다.이것은 x 에 형식 double 가 지정되어 있는 경우, x + 1 의 결과 (형식 double)는 형식 int 에 암시적으로 변환할 수 없기 때문입니다.

26.3.2 대리자(delegate) 작성식

   이 섹션은 §21.10 에 대신합니다.
대리자(delegate) 작성식 (§7.5.10.3)은 확장되어 인수에는 메서드 그룹으로서 분류되는 식, 익명 메서드나 lambda 식으로서 분류되는 식 또는 대리자(delegate) 형식의 값을 지정할 수 있게 되었습니다.
new D(E)라는 형식 (D 는 delegate-type, E 는 expression)의 delegate-creation-expression 컴파일시 처리는 다음의 순서로 행해집니다.
  • E 가 메서드 그룹의 경우는 E 에서 D 에의 메서드 그룹의 변환 (§21.9)이 존재할 필요가 있어, 대리자(delegate) 작성식은 그 변환과 같은 방법으로 처리됩니다.
  • E 가 익명 메서드 또는 lambda 식 경우는 E 에서 D 에의 익명 메서드 또는 lambda 식변환 (§26.3.1)(이)가 존재할 필요가 있어, 대리자(delegate) 작성식은 그 변환과 같은 방법으로 처리됩니다.
  • E 가 대리자(delegate) 형식의 값의 경우는 E 메서드 서명이 D 와 일치하고 있을 (§21.9) 필요가 있어, 결과는 E 와 같을 호출해 리스트를 참조하는 형식 D 가 새롭게 작성된 대리자(delegate)에의 참조입니다.E 가 D 와 일치하지 않는 경우는 컴파일시 오류가 발생합니다.

26.3.3 형식 유추

   이 섹션은 §20.6.4 에 대신합니다.
형식 인수를 지정하지 않고 제네릭 메서드를 호출하면, 형식 유추 처리에 의해, 그 호출의 형식 인수의 유추가 시도됩니다.형식 유추가 존재하는 것에 의해, 제네릭 메서드 호출로, 보다 편리한 구문을 사용할 수 있게 되어, 프로그래머는 중복 하는 형식 정보를 지정하지 않아도 됩니다.예를 들어, 다음과 같이 메서드를 선언했다고 합니다.
class Chooser
{
   static Random rand = new Random();
   public static T Choose<T>(T first, T second) {
      return (rand.Next(2) == 0)? first: second;
   }
}
이 경우, 형식 인수를 명시적으로 지정하지 않아도 다음과 같이 Choose 메서드를 호출할 수 있습니다.
int i = Chooser.Choose(5, 213);               // Choose<int> 를 호출한다
string s = Chooser.Choose("foo", "bar");      // Choose<string> 를 호출한다
형식 유추에 의해, 메서드 인수에서 형식 인수가 int, string 이라고 결정됩니다.
형식 유추는 메서드 호출 (§20.9.7) 컴파일시 처리의 일환으로서 실행되어 호출의 오버로드 해결 순서 전에 행해집니다.메서드 호출로 특정의 메서드 그룹을 지정해, 메서드 호출의 일부로서 형식 인수를 지정하지 않는 경우, 그 메서드 그룹의 각 제네릭 메서드에는 형식 유추가 적용됩니다.형식 유추가 성공했을 경우, 그 후의 오버로드 해결에서는 인수의 형식을 결정하는데, 유추된 형식 인수가 사용됩니다.오버로드 해결로, 호출하는 메서드로서 제네릭 메서드가 선택되었을 경우, 유추된 형식 인수가 그 호출의 실제의 형식 인수로서 사용됩니다.특정의 메서드 형식 유추가 실패했을 경우는 그 메서드는 오버로드 해결에 관여하지 않습니다.형식 유추가 실패한 것 만으로는 컴파일시 오류는 발생하지 않습니다만, 많은 경우, 형식 유추의 실패에 의해 오버로드 해결로 적절한 메서드가 발견되지 않고, 컴파일시 오류가 발생합니다.
지정한 인수의 수가 메서드 매개 변수의 수와 다른 경우, 유추는 즉시 실패합니다.그 이외의 경우는 제네릭 메서드가 다음과 같은 서명을 가진다고 합니다.
Tr M<X1...Xn>(T1 x1 ... Tm xm)
M(e1...em) 형식 메서드 호출에서는 형식 유추의 역할은 형식 매개 변수 X1...Xn 의 각각 대해 일의의 형식 인수 S1...Sn 를 호출 M<S1...Sn>(e1...em)가 유효하게 되도록 합니다.
유추 처리중에 각 형 매개 변수 Xi 는 특정의 형식 Si 에 고정되는지, 관련지을 수 있었던 범위세트를 가져 고정되지 않습니다.범위의 각각은 어느A 형식 T 입니다.처음은 각 형변수 Xi 는 범위의 빈 세트를 가져 고정되지 않습니다.
형식 유추는 단계적에 행해집니다.각 단계에서는 전 단계의 결과에 근거해 보다 많은 형식 변수의 형식 인수의 유추가 시행됩니다.제 1 단계에서는 범위에 대한 최초의 유추가 몇개인가 행해져 제 2 단계에서는 형식 변수가 특정의 형식에 고정되어 범위가 한층 더 유추됩니다.제 2 단계는 경우에 따라서는 몇번이나 반복되어야 합니다.
   이 이후, 이 기사내에서 "대리자(delegate) 형식"  표현을 사용했을 경우, 이것에는 Expression<D>  형식 (D 는 대리자(delegate) 형식)의 형식도 포함됩니다. Expression<D> 인수와 반환 형식은 D 와 같습니다.
   형식 유추는 제네릭 메서드 호출시인 만큼 행해지는 것은 아닙니다.메서드 그룹의 변환 형식 유추에 대해서는 §26.3.3.12 가 연속된식에 대한 최적인 공통의 형식의 알아내는 방법에 대해서는 §26.3.3.13 이 설명합니다.

26.3.3.1 제 1 단계

메서드 인수 ei 의 각각 붙고,
  • ei 가 lambda 식, 익명 메서드 또는 메서드 그룹의 경우는 Ti 형의 ei 에서 명시적 인수 형식 유추 (§26.3.3.7)(을)를 합니다.
  • ei 가 lambda 식, 익명 메서드, 메서드 그룹의 경우는 Ti 형의 ei 에서 출력 형식 유추 (§26.3.3.6)를 합니다.

26.3.3.2 제 2 단계

Xj 에 "종속성" (§26.3.3.5) 하지 않고 고정되지 않은 형식 변수 Xi 가 모두 고정됩니다 (§26.3.3.10).
이러한 형식 변수가 존재하지 않는 경우, 고정되지 않은 형식 변수 Xi 가운데, 다음의 양쪽 모두에 해당하는 것은 모두 고정됩니다.
  • Xi 에 종속성하는 형식 변수 Xj 가 적어도 1 존재합니다.
  • Xi 는 비어 있지 않은 범위세트를 가지고 있습니다.
이러한 형식 변수가 존재하지 않고, 고정되지 않은 형식 변수가 아직 존재하는 경우는 형식 유추는 실패합니다.고정되지 않은 형식 변수가 그 이상 존재하지 않는 경우는 형식 유추는 성공합니다.그 이외의 경우는 대응하는 인수의 형식 Ti 를 가져, 고정되지 않은 형식 변수 Xj 가 출력 형식 (§26.3.3.4)에는 포함되지만 입력 형식 (§26.3.3.3)에는 포함되지 않은 인수 ei 모두에게 대해서, Ti 형의 ei 에 대한, 출력 형식 유추 (§26.3.3.6)를 합니다.가 제 2 단계가 반복해집니다.

26.3.3.3 입력 형식

e 가 메서드 그룹 또는 암시적으로 형식화된 lambda 식, T 가 대리자(delegate) 형식의 경우는 T 의 인수의 형식은 모두, T 형의 e 입력 형식입니다.

26.3.3.4 출력 형식

e 가 메서드 그룹, 익명 메서드, 구문 Lambda 또는 식 Lambda이며, T 가 대리자(delegate) 형식의 경우는 T 의 반환 형식은 T 형의 e 출력 형식입니다.

26.3.3.5 종속성

Tk 형의 어느A 인수 ek 에 대해서, Tk 형의 ek 입력 형식에 Xj , Tk 형의 ek 의 출력 형식에 Xi 가 있는 경우, 고정되지 않은 형식 변수 Xi 는 고정되지 않은 형식 변수 Xj 에 "직접 종속성" 합니다.
Xj 가 Xi 에 직접 종속성하는지, Xi 가 Xk 에 직접 종속성하여 Xk 가 Xj 에 종속성하는 경우, Xj 는 Xi 에 "종속성" 합니다. 따라서,"종속성하는" 은" 직접 종속하는"  전이적(transitive)이지만, 반사폐포가 아닙니다.

26.3.3.6 출력 형식 유추

T 형식 e 에서 다음과 같은 방법으로 출력 형식 유추를 합니다.
  • e 가유추되는 반환 형식이 U (§26.3.3.11)의 Lambda 또는 익명 메서드여, T 가반환 형식이 Tb 대리자(delegate) 형식인 경우, U 에서 Tb 에 대해서 낮은 바인딩 유추 (§26.3.3.9)를 합니다.
  • 상기에 해당하지 않고, e 가 메서드 그룹이며, T 가매개 변수의 형식이 T1...Tk 의 대리자(delegate) 형식이며, 형식 T1...Tk 의 e 오버로드 해결에 의해, 반환 형식이 U 의 메서드가 1 을   U 에서 Tb 에 대해서 낮은 바인딩 유추를 합니다.
  • 상기의 어느 쪽에도 해당하지 않고, e 가 U 형식의 경우, U 에서 T 에 대해서 낮은 바인딩 유추를 합니다.
  • 상기의 어느 것에도 해당하지 않는 경우, 유추는 행해지지 않습니다.

26.3.3.7 명시적 인수 형식 유추

T 형식 e에서 다음과 같은 방법으로 명시적 인수 형식 유추를 합니다.
  • e 가인수의 형식이 U1...Uk 의 명시적으로 형식화된 lambda 식또는 익명 메서드로, T 가매개 변수의 형식이 V1...Vk 의 대리자(delegate) 형식의 경우, 각 Ui 에 대해서, Ui 에서 대응하는 Vi 에 대한 정확한 유추 (§26.3.3.8)을 합니다.

26.3.3.8 정확한 유추

형식 U 에서 형식 V 에 대한 정확한 유추는 다음과 같이 행해집니다.
  • V 가 고정되지 않은 Xi 의 한개인 경우, Xi 의 범위세트에 U 가 추가됩니다.
  • 상기에 해당하지 않고, U 가 배열형 Ue[...] 가 V 가 같은 차원의 배열형 Ve[...]의 경우, Ue 에서 Ve 에 대한 정확한 유추를 합니다.
  • 상기의 어느 쪽에도 해당하지 않고, V 가 구축된 형식 C<V1...Vk> 로, U 가 구축된 형식 C<U1...Uk> 의 경우, 각 Ui 에서 대응하는 Vi 에 대한 정확한 유추를 합니다.
  • 상기의 어느 것에도 해당하지 않는 경우, 유추는 행해지지 않습니다.

26.3.3.9 낮은 바인딩 유추

형식 U 에서 형식 V 에 대한 낮은 바인딩 유추는 다음과 같이 해 행해집니다.
  • V 가고정되지 않은 Xi 의 한개인 경우, Xi 의 범위세트에 U 가 추가됩니다.
  • 상기에 해당하지 않고, U 가 배열형 Ue[...] 이 V 가 같은 차원의 배열형 Ve[...] 의 경우 또는 U 가 1 차원 배열형 Ue[] 로 V 가 IEnumerable<Ve>, ICollection<Ve>, IList<Ve> 의 몇개의 경우,
    • Ue 가 참조형인 것을 알 수 있고 있는 경우는 Ue 에서 Ve 에 대한 낮은 바인딩 유추를 합니다.
    • 그 이외의 경우는 Ue 에서 Ve 에 대한 정확한 유추를 합니다.
  • 상기의 어느 쪽에도 해당하지 않고, V 가 구축된 형식 C<V1...Vk> 이며, U 에서 C<U1...Uk> 에의 표준 암묵 변환이 존재하는 형식의 일의세트 U1...Uk 가 존재하는 경우는 각 Ui 에서 대응하는 Vi 에 대해서 정확한 유추를 합니다.
  • 상기의 어느 것에도 해당하지 않는 경우, 유추는 행해지지 않습니다.

26.3.3.10 고정

범위세트를 가지는 고정되지 않은 형식 변수 Xi 는 다음과 같이 고정됩니다.
  • "후보의 형식" Uj 세트는 처음은 Xi  범위세트에 포함되는 모든 형식직합입니다.
  • Xi 의 각 범위를 순서에 조사합니다.X 의 각 범위 U 에 대해서, U 에서 표준 암묵 변환이 존재 "하지 않는" 형식 Uj 는 모두 후보 세트에서 제외됩니다.
  • 남아 있는 후보의 형식 Uj 안에 다른 모든 후보의 형식에의 표준 암묵 변환이 존재하는 형식 V 가 존재하는 경우는 Xi 는 V 에 고정됩니다.
  • 그 이외의 경우는 형식 유추는 실패합니다.

26.3.3.11 유추되는 반환 형식

형식 유추 및 오버로드 해결을 위해 lambda 식 또는 익명 메서드인 e 유추되는 반환 형식은 다음과 같이 결정됩니다.
  • e expression body가 식의 경우는 그 식의 형식이 e 유추되는 반환 형식입니다.
  • e expression body가 구문 블록의 경우는 그 블록의 return 구문의 식직합에 최적인 공통의 형식이 있어, 그 형식이 null 형이 아니면, 그 형식이 e 유추되는 반환 형식입니다.
  • 상기의 어느 쪽에도 해당하지 않는 경우는 e 반환 형식은 유추할 수 없습니다.
lambda 식이 관련하는 형식 유추의 예로서 다음과 같은 System.Linq.Enumerable 클래스에서 선언된 Select 확장 메서드를 생각해 봅시다.
namespace System.Linq
{
   public static class Enumerable
   {
      public static IEnumerable<TResult> Select<TSource,TResult>(
         this IEnumerable<TSource> source,
         Func<TSource,TResult> selector)
      {
         foreach (TSource element in source) yield return selector(element);
      }
   }
}
using 절을 사용하여 System.Linq 네임 스페이스를 가져오기 했다고 합니다. string 형의 Name 속성을 가지는 클래스 Customer 가 있다면, 다음과 같이 Select 메서드를 사용하여 고객 리스트의 이름을 선택할 수 있습니다.
List<Customer> customers = GetCustomerList();
IEnumerable<string> names = customers.Select(c => c.Name);
Select 의 확장 메서드 호출 (§26.2.3)은 다음과 같이 정적 메서드 호출을 고쳐 쓰는 것으로 처리됩니다.
IEnumerable<string> names = Enumerable.Select(customers, c => c.Name);
형식 인수를 명시적으로 지정하지 않았기 때문에 형식 유추를 사용하여 형식 인수가 유추됩니다.우선, customers 인수가 source 매개 변수에 관련지을 수 있어 T 는 Customer 이다고 유추됩니다. 앞에서 말한 lambda 식 형식 유추 처리를 사용하고, c 의 형식은 Customer 이다고 유추되어 식 c.Name 가 selector 매개 변수의 반환 형식에 관련지을 수 있고, S 는 string 으로 유추됩니다.따라서, 호출은 이하와 동등합니다.
Sequence.Select<Customer,string>(customers, (Customer c) => c.Name)
또, 결과의 형식은 IEnumerable<string> 입니다.
다음의 예는 lambda 식 형식 유추에 의해, 형식 정보가 제네릭 메서드 호출의 인수간에 어떻게 건네줄 수 있는지를 나타냅니다.다음과 같은 메서드가 있다고 합니다.
static Z F<X,Y,Z>(X value, Func<X,Y> f1, Func<Y,Z> f2) {
   return f2(f1(value));
}
이 경우, 다음의 호출
double seconds = F("1:15:30", s => TimeSpan.Parse(s), t => t.TotalSeconds);
의 형식 유추는 다음과 같이 행해집니다.우선, 인수 "1:15:30" 가 value 매개 변수에 관련지을 수 있어 X 는 string 이다고 유추됩니다.첫번째의 lambda 식 매개 변수 s 의 형식은 string 이다고 유추되어 식 TimeSpan.Parse(s)가 f1 의 반환 형식에 관련지을 수 있고, Y 는 System.TimeSpan 라고 유추됩니다. 마지막으로, 2 번째의 lambda 식 매개 변수 t 의 형식은 System.TimeSpan 이다고 유추되어 식 t.TotalSeconds 가 f2 의 반환 형식에 관련지을 수 있고, Z 는 double 라고 유추됩니다.따라서, 호출의 결과의 형식은 double 입니다.

26.3.3.12 메서드 그룹의 변환 형식 유추

제네릭 메서드 호출과 같이 제네릭 메서드를 포함한 메서드 그룹 M 가 특정의 대리자(delegate) 형식 D 에 대입되는 경우에도, 형식 유추가 적용될 필요가 있습니다. 
Tr M<X1...Xn>(T1 x1 ... Tm xm)
대리자(delegate) 형식 D 에 대입된 메서드 그룹 M 가 있다면, 형식 유추의 역할은 다음 식 D 에 대입 가능하게 되도록, 
M<S1...Sn>
형식 인수 S1...Sn 를 알아내는 것입니다.
제네릭 메서드 호출로의 형식 유추의 알고리즘과는 달라, 이 경우는 인수의 expressions은 존재하지 않고, 어느A 인수의 types 뿐입니다.특히, lambda 식이 없기 때문에 복수 단계의 유추는 불필요합니다.
대신에 모든 Xi 는 고정되지 않다고 보여져 D 의 인수의 형식 Uj 각각에서 M 의 대응하는 매개 변수의 형식 Tj 에 대한 낮은 바인딩 유추를 합니다.어느 Xi 에 관해서도 범위가 발견되지 않는 경우는 형식 유추는 실패합니다.그 이외의 경우는 모든 Xi 는 대응하는 Si (형식 유추의 결과)에 고정됩니다.

26.3.3.13 식직합의 최적 공통 형식

경우에 따라서는 식직합에 대한 공통의 형식을 유추해야 합니다.특히, 암시적으로 형식화된 배열의 요소 형식 및 익명 메서드나 구문 Lambda의 반환 형식은 이 방법으로 밝혀 냅니다.
직감적으로는 e1...em 라는 연속된식이 있다면, 이 유추는 인수에 ei 를 지정해 다음의 메서드
Tr M<X>(X x1 ... X xm)
를 호출하는 것과 동등하다고 생각할 수 있습니다.
엄밀하게는 유추는 고정되지 않은 형식 변수 X 에서 시작한후, X 형의 ei 각각에서 출력 형식 유추를 해 마지막으로, X 가 고정되어 결과적으로 얻을 수 있던 형식 S 가식의 공통의 형식이 됩니다.

26.3.4 오버로드 해결

특정의 상황에 있어서는 인수 리스트내의 lambda 식이 오버로드 해결에 영향을 줍니다.정확한 규칙에 대해서는 §7.4.2.3 을 참조해 주세요.
다음의 예는 Lambda가 오버로드 해결에게 주는 영향을 나타냅니다.
class ItemList<T>: List<T>
{
   public int Sum(Func<T,int> selector) {
      int sum = 0;
      foreach (T item in this) sum += selector(item);
      return sum;
   }
   public double Sum(Func<T,double> selector) {
      double sum = 0;
      foreach (T item in this) sum += selector(item);
      return sum;
   }
}
ItemList<T> 클래스에는 2 개의 Sum 메서드가 있습니다.어느 쪽의 메서드도 selector 인수를 받습니다.이 인수는 합계하는 값을 리스트 항목에서 추출합니다.추출된 값은 int 의 경우와 double 경우가 있어, 같이 합계 결과도 int 또는 double 입니다.
Sum 메서드는 예를 들어, 주문의 명세행의 리스트에서 합계를 계산하는데 사용할 수 있습니다.
class Detail
{
   public int UnitCount;
   public double UnitPrice;
   ...
}
void ComputeSums() {
   ItemList<Detail> orderDetails = GetOrderDetails(...);
   int totalUnits = orderDetails.Sum(d => d.UnitCount);
   double orderTotal = orderDetails.Sum(d => d.UnitPrice * d.UnitCount);
   ...
}
lambda 식d => d.UnitCount 는 Func<Detail,int> 와 Func<Detail,double> 의 양쪽 모두와 호환성이 있으므로, 첫번째의 orderDetails.Sum 의 호출은 어느 쪽의 Sum 메서드에도 적용할 수 있습니다.그러나, 오버로드 해결에서는 첫번째의 Sum 메서드가 선택됩니다.Func<Detail,int> 에의 변환이 Func<Detail,double> 에의 변환보다 적절하기 때문에입니다.
lambda 식d => d.UnitPrice * d.UnitCount 에 의해 생성되는 것이 double 형의 값이므로, 2 번째의 orderDetails.Sum 호출은 2 번째의 Sum 메서드 밖에 적용할 수 없습니다.따라서, 이 호출에서는 오버로드 해결에 의해 2 번째의 Sum 메서드가 선택됩니다.

26.4 개체 이니셜라이저와 컬렉션 이니셜라이저

개체 작성식 (§7.5.10.1)에는 신규 작성된 개체의 멤버 또는 신규 작성된 컬렉션의 요소를 초기화하는 개체 이니셜라이저 또는 컬렉션 이니셜라이저가 포함되는 경우가 있습니다.
object-creation-expression:
    new   type   (   argument-listopt   )   object-or-collection-initializeropt 
    new   type   object-or-collection-initializer
    
object-or-collection-initializer:
    object-initializer
    collection-initializer
개체 작성식에서는 개체 이니셜라이저 또는 컬렉션 이니셜라이저가 포함되는 경우는 생성자의 인수 리스트를 생략 할 수 있습니다.생성자의 인수 리스트  생략 하는 것은 비어있슨 인수 리스트를 지정하여 동등합니다.
개체 이니셜라이저 또는 컬렉션 이니셜라이저가 포함되는 개체 작성식을 실행하려면 , 우선 인스턴스 생성자를 호출해, 다음에 개체 이니셜라이저 또는 컬렉션 이니셜라이저에 의해 지정된 멤버 또는 요소의 초기화를 실행합니다.
개체 이니셜라이저 또는 컬렉션 이니셜라이저에서는 초기화중의 개체 인스턴스를 참조할 수 없습니다.
개체 이니셜라이저와 컬렉션 이니셜라이저를 제네릭으로 정상적으로 분석 하려면 ,§20.6.5 에 기재되어 있는 애매함을 해소하는 토큰의 리스트를 } 토큰에 의해 증강해야 합니다.

26.4.한개체 이니셜라이저

개체 이니셜라이저에서는 개체의 1 이상의 필드나 속성의 값을 지정합니다.
object-initializer:
    {   member-initializer-listopt   }
    {   member-initializer-list   ,   }

member-initializer-list:
    member-initializer
    member-initializer-list   ,   member-initializer

member-initializer:
    identifier   =   initializer-value

initializer-value:
    expression
    object-or-collection-initializer
개체 이니셜라이저는{ 토큰과 } 토큰으로 둘러싸여 콤마로 단락지어진, 연속된멤버 이니셜라이저로 구성됩니다.각 멤버 이니셜라이저에서는 초기화중의 개체의 접근 가능한 필드 또는 속성의 이름을 지정해, 그 후에 등호와 식, 혹은 개체 이니셜라이저 또는 컬렉션 이니셜라이저의 한편을 지정해야 합니다. 개체 이니셜라이저에게, 같은 필드 또는 속성의 멤버 이니셜라이저를 복수 포함하면, 오류가 됩니다.개체 이니셜라이저에서는 초기화중의 신규 작성된 개체를 참조할 수 없습니다.
등호의 뒤에 식이 지정되어 있는 멤버 이니셜라이저는 필드 또는 속성에의 대입 (§7.13.1)과 같은 방법으로 처리됩니다.
등호의 뒤에 개체 이니셜라이저가 지정되어 있는 멤버 이니셜라이저는 "상자가 된 개체 이니셜라이저", 즉 인젝션 개체를 초기화합니다. 필드나 속성에 새로운 값을 대입하는 것이 아니라, 상자가 된 개체 이니셜라이저로의 대입은 필드나 속성의 멤버에의 대입으로서 다루어집니다.상자가 된 개체 이니셜라이저는 값 형식의 속성이나, 독해 전용으로 값 형식의 필드에는 적용할 수 없습니다.
등호의 뒤에 컬렉션 이니셜라이저가 지정되어 있는 멤버 이니셜라이저는 짜넣어 컬렉션을 초기화합니다.필드나 속성에 새로운 컬렉션을 대입하는 것이 아니라, 이니셜라이저로 지정한 요소가필드나 속성에 의해 참조되는 컬렉션에 추가됩니다.필드나 속성은 §26.4.2 이 설명하는 요건을 채우는 컬렉션 형식이어야 합니다.
다음의 클래스는 2 개의 좌표를 가지는 점을 나타냅니다.
public class Point
{
   int x, y;
   public int X { get { return x; } set { x = value; } }
   public int Y { get { return y; } set { y = value; } }
}
Point 인스턴스는 다음과 같이 작성해 초기화할 수 있습니다.
var a = new Point { X = 0, Y = 1 };
이것은 다음과 같은 효과를 가집니다.
var __a = new Point();
__a.X = 0;
__a.Y = 1; 
var a = __a;
__a 는 이러한 방법을 사용하지 않으면 은폐 되어 접근 할 수 없는 임시 변수입니다.다음의 클래스는 2 개의 점에서 작성되는 사각형을 나타냅니다.
public class Rectangle
{
   Point p1, p2;
   public Point P1 { get { return p1; } set { p1 = value; } }
   public Point P2 { get { return p2; } set { p2 = value; } }
}
Rectangle 인스턴스는 다음과 같이 작성해 초기화할 수 있습니다.
var r = new Rectangle {
   P1 = new Point { X = 0, Y = 1 },
   P2 = new Point { X = 2, Y = 3 }
};
이것은 다음과 같은 효과를 가집니다.
var __r = new Rectangle();
var __p1 = new Point();
__p1.X = 0;
__p1.Y = 1;
__r.P1 = __p1;
var __p2 = new Point();
__p2.X = 2;
__p2.Y = 3;
__r.P2 = __p2; 
var r = __r;
__r, __p1, __p2 는 이러한 방법을 사용하지 않으면 은폐 되어 접근 할 수 없는 임시 변수입니다.
Rectangle 생성자가 다음과 같이 2 개의 편입의 Point 인스턴스를 할당합니다.
public class Rectangle
{
   Point p1 = new Point();
   Point p2 = new Point();
   public Point P1 { get { return p1; } }
   public Point P2 { get { return p2; } }
}
이 경우, 새로운 인스턴스를 할당하는 대신에 다음의 구문을 사용하고, 편입의 Point 인스턴스를 초기화할 수 있습니다.
var r = new Rectangle {
   P1 = { X = 0, Y = 1 },
   P2 = { X = 2, Y = 3 }
};
이것은 다음과 같은 효과를 가집니다.
var __r = new Rectangle();
__r.P1.X = 0;
__r.P1.Y = 1;
__r.P2.X = 2;
__r.P2.Y = 3;
var r = __r;

26.4.2 컬렉션 이니셜라이저

컬렉션 이니셜라이저에서는 컬렉션의 요소를 지정합니다.
collection-initializer:
    {   element-initializer-list   }
    {   element-initializer-list   ,   }

element-initializer-list:
    element-initializer
    element-initializer-list   ,   element-initializer

element-initializer:
    non-assignment-expression
    {   expression-list   }
컬렉션 이니셜라이저는{ 토큰과 } 토큰으로 둘러싸여 콤마로 단락지어진, 연속된요소 이니셜라이저로 구성됩니다.각 요소 이니셜라이저에서는 초기화중의 컬렉션 개체에 추가하는 요소를 지정합니다.또, 각 요소 이니셜라이저는{ 토큰과 } 토큰으로 둘러싸여 콤마로 단락지어진, 식의 리스트로 구성됩니다.식이 한개만의 요소 이니셜라이저는 중괄호 없이 기술할 수 있지만, 그처럼 기술했을 경우는 대입식으로 할 수 없습니다.멤버 이니셜라이저와의 헷갈림을 피하기 위해서 입니다. non-assignment-expression 작성에 대해서는 §26.3 에서 설명했습니다.
컬렉션 이니셜라이저를 포함한 개체 작성식의 예입니다.
List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
컬렉션 이니셜라이저가 적용된 컬렉션 개체는 System.Collections.IEnumerable 를 구현 하는 형식이어야 합니다.그렇지 않은 경우는 컴파일시 오류가 발생합니다.컬렉션 이니셜라이저는 지정된 각 요소에 대해 차례로, 요소 이니셜라이저의 식 리스트를 사용하여 대상 개체에 대해서 Add 메서드를 호출해, 각 호출에 대해서 일반적인 오버로드 해결을 적용합니다.
다음의 클래스는 이름과 전화 번호 리스트로 구성된 연락처를 나타냅니다.
public class Contact
{
   string name;
   List<string> phoneNumbers = new List<string>();
   public string Name { get { return name; } set { name = value; } }
   public List<string> PhoneNumbers { get { return phoneNumbers; } }
}
List<Contact> 는 다음과 같이 작성해 초기화할 수 있습니다.
var contacts = new List<Contact> {
   new Contact {
      Name = "Chris Smith",
      PhoneNumbers = { "206-555-0101", "425-882-8080" }
   },
   new Contact {
      Name = "Bob Harris",
      PhoneNumbers = { "650-555-0199" }
   }
};
이것은 다음과 같은 효과를 가집니다.
var contacts = new List<Contact>();
var __c1 = new Contact();
__c1.Name = "Chris Smith";
__c1.PhoneNumbers.Add("206-555-0101");
__c1.PhoneNumbers.Add("425-882-8080");
contacts.Add(__c1);
var __c2 = new Contact();
__c2.Name = "Bob Harris";
__c2.PhoneNumbers.Add("650-555-0199");
contacts.Add(__c2);
__c1 와 __c2 는 이러한 방법을 사용하지 않으면 은폐 되어 접근 할 수 없는 임시 변수입니다.

26.5 익명형식

C# 3.0 에서는 익명형식의 개체를 작성하기 위해 new 연산자를 이름이 없는 개체 이니셜라이저와 함께 사용할 수 있습니다.
primary-no-array-creation-expression:
    ...
    anonymous-object-creation-expression

anonymous-object-creation-expression:
    new   anonymous-object-initializer

anonymous-object-initializer:
    {   member-declarator-listopt   }
    {   member-declarator-list   ,   }

member-declarator-list:
    member-declarator
    member-declarator-list   ,   member-declarator

member-declarator:
    simple-name
    member-access
    identifier   =   expression
이름이 없는 개체 이니셜라이저에서는 익명형식을 선언해, 그 형식의 인스턴스를 돌려줍니다.익명형식은 object 에서 직접 상속하는 무명의 클래스형입니다.익명형식의 멤버는 그 형식의 인스턴스의 작성에 사용되는 개체 이니셜라이저에서 유추되는 일련의 읽기 속성입니다.구체적으로는
new { p1 = e1 , p2 = e2 , ... pn = en }
이름이 없는 개체 이니셜라이저에서는 다음과 같은 형식의 익명형식이 선언됩니다.
class __Anonymous1
{
   private T1 f1 ;
   private T2 f2 ;
   ...
   private Tn fn ;
   public T1 p1 { get { return f1 ; } set { f1 = value ; } }
   public T2 p2 { get { return f2 ; } set { f2 = value ; } }
   ...
   public T1 p1 { get { return f1 ; } set { f1 = value ; } }
}
각 Tx 는 대응하는 식 ex 의 형식입니다.이름이 없는 개체 이니셜라이저안의 식이 null 형이나 unsafe 형의 경우, 컴파일시 오류가 발생합니다.
익명형식의 이름은 컴파일러에 의해 자동적으로 생성되어 프로그램 텍스트내에서 참조할 수 없습니다.
같은 프로그램내의 같은 이름으로 컴파일시 형식도 같은 연속된속성을 같은 순서로 지정하는 이름이 없는 개체 이니셜라이저 2 는 같은 익명형식의 인스턴스를 생성합니다 (리플렉션 등 특정의 상황에서는 속성의 순서가 중요해서, 이 정의에는 속성의 순서가 포함됩니다).
다음은 예를 나타냅니다.
var p1 = new { Name = "Lawnmower", Price = 495.00 };
var p2 = new { Name = "Shovel", Price = 26.95 };
p1 = p2;
이 예에서는 p1 와 p2 는 같은 익명형식이므로, 마지막 행의 대입은 허가됩니다.
모든 속성이 동일한 경우만, 같은 익명형식의 2 개의 인스턴스가 동일해지도록, 익명형식의 Equals 메서드와 GetHashcode 메서드는 속성의 Equals 와 GetHashcode 라는 관점에서 정의됩니다..
멤버 선언자는 간이명 (§7.5.2) 또는 멤버 접근 (§7.5.4)의 형식으로 축약할 수 있습니다.이것은 "프로젝션 이니셜라이저" 로 불려 같은 이름을 사용한 속성의 선언과 속성에의 대입의 축약법입니다.구체적으로 보면,
identifier                        expr . identifier
그렇다고 하는 형식의 멤버 선언자는 각각, 이하와 완전히 동등합니다.
identifer = identifier               identifier = expr . identifier
따라서, 프로젝션 이니셜라이저에서는 identifier는 값 뿐만이 아니라, 값의 대입처의 필드나 속성도 선택합니다.직감적으로는 프로젝션 이니셜라이저는 값 뿐만이 아니라 값의 이름도 예측합니다.

26.6 암시적으로 형식화된 배열

배열 작성식 (§7.5.10.2)구문은 확장되어 암시적으로 형식화된 배열 작성식이 지원됩닌다.
array-creation-expression:
    ...
    new   [   ]   array-initializer
암시적으로 형식화된 배열 작성식에서는 배열 인스턴스의 형식은 배열 이니셜라이저로 지정된 요소에서 유추됩니다.구체적으로는 배열 이니셜라이저내의 식의 형식에 의해 형성되는 세트에는 세트에 포함되는 각 형에서 암시적으로 변환 가능한 형식이 한개만 포함되어 있을 필요가 있어, 그 형식이 null 형이 아닌 경우, 그 형식의 배열이 작성됩니다.형식이 한개만 유추할 수 없었던 경우나, 유추된 형식이 null 형의 경우는 컴파일시 오류가 발생합니다.
암시적으로 형식화된 배열 작성식의 예입니다.
var a = new[] { 1, 10, 100, 1000 };            // int[]
var b = new[] { 1, 1.5, 2, 2.5 };            // double[]
var c = new[] { "hello", null, "world” };      // string[]
var d = new[] { 1, "one", 2, "two" };         // 오류
마지막 식에서는 컴파일시 오류가 발생합니다. int 와 string 에서는 어느 쪽에도 암시적으로 변환할 수 없기 때문입니다.이 경우는 명시적으로 형식화된 배열 작성식을 사용하여야 합니다.예를 들어, 형식을 object[] 와 지정합니다.또는 요소의 한개를 공통의 기본형에 캐스트 하는 방법도 있습니다.
암시적으로 형식화된 배열 작성식을 이름이 없는 개체 이니셜라이저와 조합하고, 익명형식으로서 형식화된 데이터 구조를 작성할 수 있습니다.다음은 예를 나타냅니다.
var contacts = new[] {
   new {
      Name = "Chris Smith",
      PhoneNumbers = new[] { "206-555-0101", "425-882-8080" }
   },
   new {
      Name = "Bob Harris",
      PhoneNumbers = new[] { "650-555-0199" }
   }
};

26.7 쿼리 식

쿼리 식은 SQL 나 XQuery 등의 관계형 쿼리 언어 및 계층 쿼리 언어를 닮은 언어에 통합된 쿼리 용무의 구문을 제공합니다.
query-expression:
    from-clause   query-body

from-clause:
    from   typeopt   identifier   in   expression

query-body:
    query-body-clausesopt   select-or-group-clause   query-continuationopt

query-body-clauses:
    query-body-clause
    query-body-clauses   query-body-clause

query-body-clause:
    from-clause
    let-clause
    where-clause
    join-clause
    join-into-clause
    orderby-clause

let-clause:
    let   identifier   =   expression

where-clause:
    where   boolean-expression

join-clause:
    join   typeopt   identifier   in   expression   on   expression   equals   expression 

join-into-clause:
    join   typeopt   identifier   in   expression   on   expression   equals   expression   into   identifier

orderby-clause:
    orderby   orderings

orderings:
    ordering
    orderings   ,   ordering

ordering:
    expression    ordering-directionopt

ordering-direction:
    ascending
    descending

select-or-group-clause:
    select-clause
    group-clause

select-clause:
    select   expression

group-clause:
    group   expression   by   expression

query-continuation:
    into   identifier   query-body
query-expression non-assignment-expression (§26.3  정의 참조)에 분류됩니다.
쿼리 식은 from 절로 시작되어, select 절 또는 group 절로 끝납니다.최초의 from 절의 후에는 from 절, let 절, where 절 또는 join 절을 0 개 이상 계속할 수 있습니다.각 from 절은 특정의 순서로 사용하는 범위 변수를 제기하는 제네레이터입니다.각 let 절에서는 값을 계산해, 그 값을 나타내는 식별자(dentifiers)를 제기합니다.각 where 절은 결과에서 항목을 제외하는 필터입니다.각 join 절에서는 소스 순서의 지정된 키가 다른 순서의 키라고 비교되어 일치하는 페어를 나타냅니다.각 orderby 절에서는 지정한 조건에 따라서 항목을 늘어놓아 바꿉니다.마지막 select 절 또는 group 절에서는 범위 변수의 관점에서 결과의 형식을 지정합니다.마지막으로, into 절은 한개의 쿼리의 결과를 그 다음의 쿼리로의 제네레이터로서 취급하여, 쿼리를 "접합하는" 것에 사용할 수 있습니다.

쿼리 식에서의 애매함

쿼리 식에는 새로운 문맥 키워드 (특정의 문맥으로 특별한 의미를 가지는 식별자(dentifiers))가 몇개인가 포함되어 있습니다.이러한 새로운 문맥 키워드에는 from, join, on, equals, into, let, orderby, ascending, descending, select, group 및 by 가 있습니다.쿼리 식 내부에 기록되어 있는 일에서 이러한 식별자(dentifiers)를 키워드나 간이명이라고 해도 사용하며 생기는 애매함을 피하기 위해 이러한 식별자(dentifiers)는 쿼리 식 내부에 기록되어 있는 일에서는 항상 키워드라고 보여집니다.
따라서, 쿼리 식은 fromidentifier가 시작되어, 그 후에 ;,=,, 이외의 토큰이 계속 되는 모든 식입니다.
쿼리 식 내부에 기록되어 있는 일에서 이러한 단어를 식별자(dentifiers)로서 사용하려면, 프리픽스(Prefix) @ 를 붙이는방법이 있습니다 (§2.4.2).

26.7.1 쿼리 식 변환

C# 3.0 언어에서는 쿼리 식의 정확한 실행 시멘틱스는 지정되지 않습니다.C# 3.0 에서는 쿼리 식은 "쿼리 식 패턴" 에 따르는 메서드 호출에 변환됩니다.구체적으로는 쿼리 식은 §26.7.2 에서 설명하도록, 특정의 서명 및 결과의 형식을 가질 것으로 예상되는 Where, Select, SelectMany, Join, GroupJoin, OrderBy, OrderByDescending, ThenBy, ThenByDescending, GroupBy 및 Cast 라는 이름의 메서드 호출에 변환됩니다.이러한 메서드는 쿼리 안의 개체의 인스턴스 메서드에서도, 개체의 외부에 있는 확장 메서드에서도 괜찮습니다.이러한 메서드는 쿼리의 실제의 실행을 구현 합니다.
쿼리 식에서 메서드 호출에의 변환은 형식 바인드나 오버로드 해결이 실행되기 전에 행해지는 구문 매핑입니다.변환은 구문적으로 올바른 것이 보장 되지만 변환에 의해 의미적으로 올바른 C# 코드가 생성되는 것은 보장 되지 않습니다.쿼리 식이 변환되면, 그 결과적으로 실행되는 메서드 호출은 일반적인 메서드 호출로 처리되지만 이것에 의해 이번은 오류가 발견되는 경우가 있습니다.예를 들어, 메서드가 존재하지 않는 경우, 인수의 형식이 잘못되어 있는 경우, 메서드가 제네릭으로 형식 유추가 실패했을 경우 등입니다.
쿼리 식은 그 이상의 분해가 불가능하게 될 때까지, 변환을 반복해 실시하여, 처리됩니다.변환은 우선도순에  각 섹션은 전의 섹션의 변환이 완전하게 실행된 것을 전제로 합니다.
특정의 종류의 변환에서는* 에 나타내지는 투명한 식별자(dentifiers)에 의해 범위 변수가 삽입됩니다.투명한 식별자(dentifiers)의 특수한 성질에 대해서는 §26.7.1.7 이 설명합니다.

26.7.1.1 연속된 select 절과 groupby 절


from ... into x ...
연속된 쿼리 식은 다음과 같이 변환됩니다.
from x in ( from ...) ...
이 이후의 섹션에서의 변환은 쿼리에 into 가 없는 것을 전제로 합니다.
다음의 예
from c in customers
group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() }
는 다음과 같이 변환됩니다.
from g in
   from c in customers
   group c by c.Country
select new { Country = g.Key, CustCount = g.Count() }
이것은 최종적으로는 다음과 같이 변환됩니다.
customers.
GroupBy(c => c.Country).
Select(g => new { Country = g.Key, CustCount = g.Count() })

26.7.1.2 범위 변수의 명시적 형식

범위 변수의 형식을 명시적으로 지정하는 from 절을 다음에 나타냅니다.
from T x in e
이것은 다음과 같이 변환됩니다.
from x in ( e ) . Cast < T > ( )
범위 변수의 형식을 명시적으로 지정하는 join 절을 다음에 나타냅니다.
join T x in e on k1 equals k2
이것은 다음과 같이 변환됩니다.
join x in ( e ) . Cast < T > ( ) on k1 equals k2
이 이후의 섹션에서의 변환은 쿼리에 범위 변수의 명시적 형식이 없는 것을 전제로 합니다.
다음의 예는
from Customer c in customers
where c.City == "London"
select c
 다음과 같이 변환됩니다.
from c in customers.Cast<Customer>()
where c.City == "London"
select c
이것은 최종적으로는 다음과 같이 변환됩니다.
customers.
Cast<Customer>().
Where(c => c.City == "London")
범위 변수의 명시적 형식은 제네릭 IEnumerable<T> 인터페이스는 아니고 non-generic IEnumerable 인터페이스를 구현 하는 컬렉션을 쿼리 하는데는 편리합니다.위의 예에서는 customers 가 ArrayList 형의 경우는 이것에 해당합니다.

26.7.1.3 역쿼리식

다음의 형식의 쿼리 식이 있다고 합니다.
from x in e select x
이것은 다음과 같이 변환됩니다.
( e ) . Select ( x => x )
다음의 예는 
from c in customers
select c
다음과 같이 변환됩니다.
customers.Select(c => c)
역쿼리식은 자명대로, 소스의 요소를 선택하는 쿼리 식입니다.변환의 뒤의 단계에서는 다른 변환 스텝에 의해 제공된 역쿼리는 소스에 옮겨놓는 것으로 삭제됩니다.다만, 쿼리 식의 결과가 소스 개체 자체가 되지 않게 하는 것은 중요합니다.쿼리 식의 결과가 소스 개체 자체의 경우, 소스의 형식과 ID 가 쿼리 바탕으로 대해 시작되어 버리기때문입니다.거기서, 이 스텝에서는 소스에 대해서 Select 를 명시적으로 호출하여, 소스 코드에 직접 기술된 역쿼리를 보호합니다.이러한 메서드가 절대로 소스 개체 자체를 돌려주지 않게 하는 것은 Select 나 다른 쿼리 연산자의 구현 사람의 책임이 됩니다.

26.7.1.4 from 절, let 절, where 절, join 절, orderby 절

2 번째의 from 절의 후에 select 절이 계속 되는 쿼리 식을 다음에 나타냅니다.
from x1 in e1
from x2 in e2
select v
이것은 다음과 같이 변환됩니다.
( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => v )
2 번째의 from 절의 후에 select 절 이외의 것이 계속 되는 쿼리 식을 다음에 나타냅니다.
from x1 in e1
from x2 in e2
...
이것은 다음과 같이 변환됩니다.
from * in ( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => new { x1 , x2 } )
...
let 절이 있는 쿼리 식을 다음에 나타냅니다.
from x in e
let y = f
...
이것은 다음과 같이 변환됩니다.
from * in ( e ) . Select ( x => new { x , y = f } )
...
where 절이 있는 쿼리 식을 다음에 나타냅니다.
from x in e
where f
...
이것은 다음과 같이 변환됩니다.
from x in ( e ) . Where ( x => f )
...
into 가 없는 join 절이 select 절이 후에 계속 되는 쿼리 식을 다음에 나타냅니다.
from x1 in e1
join x2 in e2 on k1 equals k2
select v
이것은 다음과 같이 변환됩니다.
( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => v )
into 가 없는 join 절이 select 절 이외의 것이 후에 계속 되는 쿼리 식을 다음에 나타냅니다.
from x1 in e1
join x2 in e2 on k1 equals k2 
...
이것은 다음과 같이 변환됩니다.
from * in ( e1 ) . Join(
   e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => new { x1 , x2 })
...
into 가 있는 join 절이  select 절이 후에 계속 되는 쿼리 식을 다음에 나타냅니다.
from x1 in e1
join x2 in e2 on k1 equals k2 into g
select v
이것은 다음과 같이 변환됩니다.
( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => v )
into 가 있는 join 절, select 절 이외의 것이 후에 계속 되는 쿼리 식을 다음에 나타냅니다.
from x1 in e1
join x2 in e2 on k1 equals k2 into g
...
이것은 다음과 같이 변환됩니다.
from * in ( e1 ) . GroupJoin(
   e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => new { x1 , g })
...
orderby 절이 있는 쿼리 식을 다음에 나타냅니다.
from x in e
orderby k1 , k2 , ... , kn
...
이것은 다음과 같이 변환됩니다.
from x in ( e ) . 
OrderBy ( x => k1 ) . 
ThenBy ( x => k2 ) .
 ... . 
ThenBy ( x => kn )
...
ordering 절로 descending 방향 인디케이터(indicator)를 지정하면, OrderByDescending 또는 ThenByDescending 의 호출이 대신에 생성됩니다.
이 이후가 계속 되는 변환은 각 쿼리식에 let 절, where 절, join 절, orderby 절은 존재하지 않고, 최초의 from 절이 복수는 존재하지 않는 것을 전제로 합니다.
다음의 예는
from c in customers
from o in c.Orders
select new { c.Name, o.OrderID, o.Total }
 다음과 같이 변환됩니다.
customers.
SelectMany(c => c.Orders,
    (c,o) => new { c.Name, o.OrderID, o.Total }
)
다음의 예는
from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }
다음과 같이 변환됩니다.
from * in customers.
   SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }
이것은 최종적으로는 다음과 같이 변환됩니다.
customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(x => x.o.Total).
Select(x => new { x.c.Name, x.o.OrderID, x.o.Total })
x 는 이러한 방법을 사용하지 않으면 은폐 되어 접근 할 수 없는 컴파일러에 의해 생성된 식별자(dentifiers)입니다.
다음의 예는 
from o in orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
where t >= 1000
select new { o.OrderID, Total = t }
다음과 같이 변환됩니다.
from * in orders.
   Select(o => new { o, t = o.Details.Sum(d => d.UnitPrice * d.Quantity) })
where t >= 1000 
select new { o.OrderID, Total = t }
이것은 최종적으로는 다음과 같이 변환됩니다.
orders.
Select(o => new { o, t = o.Details.Sum(d => d.UnitPrice * d.Quantity) }).
Where(x => x.t >= 1000).
Select(x => new { x.o.OrderID, Total = x.t })
x 는 이러한 방법을 사용하지 않으면 은폐 되어 접근 할 수 없는 컴파일러에 의해 생성된 식별자(dentifiers)입니다.
다음의 예는 
from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total }
다음과 같이 변환됩니다.
customers.Join(orders, c => c.CustomerID, o => o.CustomerID,
   (c, o) => new { c.Name, o.OrderDate, o.Total })
다음의 예는 
from c in customers
join o in orders on c.CustomerID equals o.CustomerID into co
let n = co.Count()
where n >= 10
select new { c.Name, OrderCount = n }
다음과 같이 변환됩니다.
from * in customers.
   GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,
      (c, co) => new { c, co })
let n = co.Count()
where n >= 10 
select new { c.Name, OrderCount = n }
이것은 최종적으로는 다음과 같이 변환됩니다.
customers.
GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,
   (c, co) => new { c, co }).
Select(x => new { x, n = x.co.Count() }).
Where(y => y.n >= 10).
Select(y => new { y.x.c.Name, OrderCount = y.n)
x 와 y 는 이러한 방법을 사용하지 않으면 은폐 되어 접근 할 수 없는 컴파일러에 의해 생성된 식별자(dentifiers)입니다.
다음의 예는 
from o in orders
orderby o.Customer.Name, o.Total descending
select o
최종적으로는 다음과 같이 변환됩니다.
orders.
OrderBy(o => o.Customer.Name).
ThenByDescending(o => o.Total)

26.7.1.5 select 절

다음의 형식의 쿼리 식이 있다고 합니다.
from x in e select v
이것은 다음과 같이 변환됩니다.
( e ) . Select ( x => v )
다만, v 가 식별자(dentifiers) x 의 경우는 변환은 단지 다음과 같이 됩니다.
( e )
예를 들어, 다음의 예는 
from c in customers.Where(c => c.City == "London")
select c
 단지 다음과 같이 변환됩니다.
customers.Where(c => c.City == "London")

26.7.1.6 groupby 절

다음의 형식의 쿼리 식이 있다고 합니다.
from x in e group v by k
이것은 다음과 같이 변환됩니다.
( e ) . GroupBy ( x => k , x => v )
다만, v 가 식별자(dentifiers) x 의 경우는 변환은 다음과 같이 됩니다.
( e ) . GroupBy ( x => k )
다음의 예는
from c in customers
group c.Name by c.Country
다음과 같이 변환됩니다.
customers.
GroupBy(c => c.Country, c => c.Name)

26.7.1.7 투명한 식별자(dentifiers)

특정의 종류의 변환에서는* 이 나타내지는 투명한 식별자(dentifiers)에 의해 범위 변수가 삽입됩니다.투명한 식별자(dentifiers)는 정식적 언어 기능이 아니고, 단지 쿼리 식 변환 프로세스에서의 중간 스텝으로서 존재합니다.
쿼리의 변환에 의해 투명한 식별자(dentifiers)가 삽입되면, 그 후의 변환 스텝으로 투명한 식별자(dentifiers)가 lambda 식및 이름이 없는 개체 이니셜라이저에게 반영됩니다.이러한 문맥으로, 투명한 식별자(dentifiers)는 다음과 같이 동작합니다.
  • 투명한 식별자(dentifiers)가 lambda 식 매개 변수로서 존재하는 경우, 관련하는 익명형식의 멤버는 자동적으로 lambda 식expression body안의 범위에 들어갑니다.
  • 투명한 식별자(dentifiers)를 가지는 멤버가 범위 안에 있는 경우, 그 멤버도 범위 안에 있는 것이 됩니다.
  • 투명한 식별자(dentifiers)가 이름이 없는 개체 이니셜라이저의 멤버 선언자로서 존재하는 경우, 투명한 식별자(dentifiers)를 가지는 멤버가 제공됩니다.
다음의 예는
from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.Total }
다음과 같이 변환됩니다.
from * in
   from c in customers
   from o in c.Orders
   select new { c, o }
orderby o.Total descending
select new { c.Name, o.Total }
이것은 또한 다음과 같이 변환됩니다.
customers.
SelectMany(c => c.Orders.Select(o => new { c, o })).
OrderByDescending(* => o.Total).
Select(* => new { c.Name, o.Total })
이것은 투명한 식별자(dentifiers)가 소거되면, 이하와 동등합니다.
customers.
SelectMany(c => c.Orders.Select(o => new { c, o })).
OrderByDescending(x => x.o.Total).
Select(x => new { x.c.Name, x.o.Total })
x 는 이러한 방법을 사용하지 않으면 은폐 되어 접근 할 수 없는 컴파일러에 의해 생성된 식별자(dentifiers)입니다.
다음의 예는
from c in customers
join o in orders on c.CustomerID equals o.CustomerID
join d in details on o.OrderID equals d.OrderID
join p in products on d.ProductID equals p.ProductID
select new { c.Name, o.OrderDate, p.ProductName }
다음과 같이 변환됩니다.
from * in
   from * in
      from * in
         from c in customers
         join o in orders o c.CustomerID equals o.CustomerID
         select new { c, o }
      join d in details on o.OrderID equals d.OrderID
      select new { *, d }
   join p in products on d.ProductID equals p.ProductID
   select new { *, p }
select new { c.Name, o.OrderDate, p.ProductName }
이것은 또한 다음과 같이 분해됩니다.
customers.
Join(orders, c => c.CustomerID, o => o.CustomerID,
   (c, o) => new { c, o }).
Join(details, * => o.OrderID, d => d.OrderID,
   (*, d) => new { *, d }).
Join(products, * => d.ProductID, p => p.ProductID,
   (*, p) => new { *, p }).
Select(* => new { c.Name, o.OrderDate, p.ProductName })
이것은 최종적으로는 다음과 같이 변환됩니다.
customers.
Join(orders, c => c.CustomerID, o => o.CustomerID,
   (c, o) => new { c, o }).
Join(details, x => x.o.OrderID, d => d.OrderID,
   (x, d) => new { x, d }).
Join(products, y => y.d.ProductID, p => p.ProductID,
   (y, p) => new { y, p }).
Select(z => new { z.y.x.c.Name, z.y.x.o.OrderDate, z.p.ProductName })
x, y, z 는 이러한 방법을 사용하지 않으면 은폐 되어 접근 할 수 없는 컴파일러에 의해 생성된 식별자(dentifiers)입니다.

26.7.2 쿼리 식 패턴

쿼리 식 패턴에서는 쿼리 식을 지원 하기 위해 형식이 구현 할 수 있는 메서드 패턴이 규정됩니다..쿼리 식은 구문 매핑에 의해 메서드 호출에 변환되므로, 쿼리 식 패턴의 구현 방법에 관해서, 형식은 매우 유연합니다.예를 들어, 인스턴스 메서드도 확장 메서드도 호출 구문이 같아서, 패턴의 메서드는 인스턴스 메서드와 확장 메서드의 어느 쪽이라고 해도 구현 할 수 있습니다.또, lambda 식은 대리자(delegate)에도 식 트리에도 변환 가능해서, 메서드는 대리자(delegate)와 식 트리의 어느쪽이나 요청 할 수 있습니다.
쿼리 식 패턴을 지원하는 제네릭형 C<T> 의 추천 되는 형식을 다음에 나타냅니다.매개 변수와 결과의 형식과의 적절한 관계를 나타내기 위해 제네릭형을 사용하지만, non-generic형 패턴을 구현 하는 것도 가능합니다.
delegate R Func<T1,R>(T1 arg1);
delegate R Func<T1,T2,R>(T1 arg1, T2 arg2);
class C
{
   public C<T> Cast<T>();
}
class C<T>
{
   public C<T> Where(Func<T,bool> predicate);
   public C<U> Select<U>(Func<T,U> selector);
   public C<U> SelectMany<U,V>(Func<T,C<U>> selector,
      Func<T,U,V> resultSelector);
   public C<V> Join<U,K,V>(C<U> inner, Func<T,K> outerKeySelector,
      Func<U,K> innerKeySelector, Func<T,U,V> resultSelector);
   public C<V> GroupJoin<U,K,V>(C<U> inner, Func<T,K> outerKeySelector,
      Func<U,K> innerKeySelector, Func<T,C<U>,V> resultSelector);
   public O<T> OrderBy<K>(Func<T,K> keySelector);
   public O<T> OrderByDescending<K>(Func<T,K> keySelector);
   public C<G<K,T>> GroupBy<K>(Func<T,K> keySelector);
   public C<G<K,E>> GroupBy<K,E>(Func<T,K> keySelector,
      Func<T,E> elementSelector);
}
class O<T> : C<T>
{
   public O<T> ThenBy<K>(Func<T,K> keySelector);
   public O<T> ThenByDescending<K>(Func<T,K> keySelector);
}
class G<K,T> : C<T>
{
   public K Key { get; }
}
상기의 메서드에서는 제네릭 대리자(delegate) 형식의 Func<T1, R> 와 Func<T1, T2, R> 를 사용하지만 , 매개 변수나 결과의 형식의 관계가 같으면, 다른 대리자(delegate) 형식 또는 식 트리형도 이와 같이 사용할 수 있습니다.
C<T> 와 O<T> 와의 추천 되는 관계에서는 ThenBy 메서드와 ThenByDescending 메서드는 OrderBy 또는 OrderByDescending 의 결과에 대해서만 사용 가능하다는 것에 주의해 주세요. 또, GroupBy 의 결과의 추천 되는 형식에도 주의해 주세요. 각각의 내부 순서는 추가의 Key 속성을 가집니다.
표준 쿼리 연산자 (다른 시방서로 설명)를 사용하면, System.Collections.Generic.IEnumerable<T> 인터페이스를 구현하는 모든 형식에 쿼리 연산자 패턴을 구현 할 수 있습니다.

26.8 식 트리

식 트리를 사용하면, lambda 식을 실행 가능 코드는 아니고 데이터 구조로서 표현할 수 있습니다.대리자(delegate) 형식 D 에 변환 가능한 lambda 식은 System.Query.Expression<D> 형식 트리에도 변환 가능합니다.lambda 식을 대리자(delegate) 형식으로 변환하면, 실행 가능 코드가 생성되어 대리자(delegate)에 의해 그 코드가 참조되지만 식 트리형으로 변환하면, 식 트리의 인스턴스를 작성하는 코드가 생성됩니다.식 트리는 lambda 식 효율적인 메모리내 데이터 표현으로식의 구조를 알기 쉽고 명백하게 합니다.
다음과 같은 예는 실행 가능 코드로서의 lambda 식와 식 트리로서의 lambda 식을 나타냅니다. Func<int,int> 에의 변환이 존재하므로, Expression<Func<int,int>> 에의 변환도 존재합니다.
Func<int,int> f = x => x + 1;                  // 코드
Expression<Func<int,int>> e = x => x + 1;      // 데이터
이러한 대입에 따라서, 대리자(delegate) f 는 x + 1 을 돌려주는 메서드를 참조해, 식 트리 e 는 식 x + 1 을 표현하는 데이터 구조를 참조합니다.

26.8.1 오버로드 해결

오버로드 해결을 위해 Expression<D> 형에 관해서 특별한 규칙이 있습니다.구체적으로는 적절함의 정의에 다음과 같은 규칙이 더해집니다.
  • D1 가 D2 보다 적절하며  Expression<D1>는 Expression<D2> 보다 적절하고, Expression<D1> 가 Expression<D2> 보다 적절한 것은 그 경우에 한정합니다.
   Expression<D> 와 대리자(delegate) 형식과의 사이에는 적절함의 규칙은 없습니다.

26.9 자동적으로 구현된 속성

많은 경우, 속성은 다음과 같은 예와 같이 지원 필드 간단한 사용에 의해 구현 됩니다.
public Class Point {
   private int x;
   private int y;
   public int X { get { return x; } set { x = value; } }
   public int Y { get { return y; } set { y = value; } }
}
자동적으로 구현된 (자동 구현) 속성을 사용하면, 이 패턴이 자동화됩니다.구체적으로는 비추상 속성 선언으로 세미콜론 접근자 expression body를 보관 유지할 수 있습니다.양쪽 모두의 접근자가 존재할 필요가 있어, 양쪽 모두에 세미콜론 expression body가 필요합니다만, 각각 다른 필요 옵션 수식자를 지정할 수 있습니다.속성을 이와 같이 지정하면, 속성의 지원 필드가 자동적으로 생성되어 그 지원 필드에의 독해나 기입을 실시하는 접근자가 구현 됩니다. 지원 필드 이름은 컴파일러에 의해 생성되어 사용자는 접근 할 수 없습니다.
다음과 같은 선언은 위의 예와 동등합니다.
 public Class Point {
   public int X { get; set; }
   public int Y { get; set; }
}
지원 필드에는 접근 할 수 없기 때문에 지원 필드에의 독해나 기입은 속성 접근자를 통해서 실시해야 합니다.즉, 독해 전용이나 써 전용의 자동 구현 속성은 의미가 없기 때문에 허가되지 않는 것을 의미합니다.다만, 각 접근자에 다른 접근 수준을 설정하는 것은 가능합니다.따라서, 다음과 같이 개인 지원 필드가 가지는 독해 전용 속성 효과를 가져올수 있습니다.
Public class ReadOnlyPoint {
   public int X { get; private set; }
   public int Y { get; private set; }
   public ReadOnlyPoint(int x, int y) { X = x; Y = y; }
}
이 제한은 자동 구현의 속성에 의한, 구조 형식의 명시적 대입은 구조의 표준 생성자를 사용하여서만 실현될 수 있는 것도 의미합니다.이것은 속성 자체에의 대입을 실시하려면, 구조가 명시적으로 대입되어 있어야 합니다.

▣  updatePanel 개요 - .NET/ASP.NET - 2011. 6. 14. 20:29
출처 : http://neostyx.tistory.com/21

글에 대한 내용은 http://www.neostyx.net/GrayRound/NXBlogPostView.aspx?postid=070405080805986&categoryname=ASP.NET+AJAX 를 눌러서 보시기 바랍니다.

포스트를 읽기에 앞서...
- 이 포스트는 영문으로 작성되어 제공되어진 것을 제가 제 나름대로 한글로 번역하였습니다.
- 직역보다는 의역에 충실하도록 노력을 하였으며, 충분하게 잘못된 번역이 있을 수 있습니다. 잘못된 번역 부분에 대해서는 덧글로 달아주시면 수정하도록 하겠습니다.
- 이 포스트에는 깔끔하게 번역되지 않은 부분이 있을 수 있습니다. 크게 양해해주시고, 영문 웹 페이지를 참조하시기 바라며, 영문 웹 페이지의 링크에 대한 경로는 필요하지 않은 이상 링크를 추가하지 않았습니다.
- 이 포스트는 단지 번역을 한 것 뿐이며, 모든 저작권에 대해서는 영문 웹 페이지에 명시된 곳에 있습니다.

UpdatePanel 컨트롤 개요

소개

ASP.NET UpdatePanel 컨트롤은 풍부하고 고객 중심인 웹 응용 프로그램을 만드는 것을 가능하게 합니다. UpdatePanel 컨트롤을 사용함으로 포스트백에 의한 전 페이지를 새로고침하는 것 대신 페이지 중 선택된 일부분만 새로고침을 할 수 있습니다. 이것은 페이지 중 일부분만 업데이트 작업을 수행하는 것을 의미합니다. ScriptManager 컨트롤과 하나 또는 그 이상의 UpdatePanel 컨트롤들이 포함된 웹 페이지는 고객측의 클라이언트 스크립트 없이도, 자동적으로 부분 페이지의 업데이트에 참여하게 됩니다.

이 토픽은 다음과 같은 정보를 포함하고 있습니다.

  1. 시나리오
  2. 배경
  3. 코드 예제
  4. 클래스 참조

시나리오

UpdatePanel 컨트롤은 웹 페이지가 최종 사용자에게 더 양방향적으로 보이게 만들어야 하는 복잡한 클라이언트 행위를 가진 웹 페이지를 개발하는 데 도움을 주는 서버 컨트롤입니다. 서버와 클라이언트 사이에서 웹 페이지의 특정 부분을 업데이트하기 위해서 보통 깊은 수준의 ECMAScript(Javascript)를 요구하였습니다. 그러나, UpdatePanel 컨트롤을 사용함으로 어떠한 클라이언트 스크립트를 작성할 필요 없이 웹 페이지에서 부분 페이지만 업데이트하는 것이 가능하게 되었습니다. 원한다면, 클라이언트의 사용자 환경을 향상시키기 위해 일반적인 클라이언트 스크립트를 추가할 수도 있습니다. UpdatePanel 컨트롤을 사용할 때, 페이지의 행동은 브라우저에 독립적이고, 클라이언트와 서버 사이에 전송되는 데이터의 양을 잠재적으로 감소시킬 수 있습니다.

배경

UpdatePanel 컨트롤은 전체 웹 페이지의 새로고침 없이 업데이트될 수 있는 특정 범위에서 작업합니다. 이 프로세스는 ScriptManager 서버 컨트롤과 PageRequestManager 클래스에 의해 공동으로 처리됩니다. 부분 페이지의 업데이트가 가능할 때, 컨트롤들은 비동기적으로 서버로 게시됩니다. 비동기적인 포스트백 행동은 페이지와 컨트롤의 생명 주기가 완료될 때의 통상적인 포스트백과 같습니다. 그러나, 비동기 포스트백에서, 페이지에서 UpdatePanel 컨트롤에 둘러쌓인 페이지의 범위만 업데이트됩니다. 서버는 브라우저로 단지 영향받은 요소들만을 HTML 마크업 형태로 보냅니다. 브라우저에서, PageRequestManager 클래스는 업데이트된 마크업으로 기존의 HTML을 교체하는 작업인 Document Object Model(DOM) 조정을 수행합니다. 아래의 그림은 첫번째에 페이지를 로드할 때와 그 다음 비동기 포스트백이 UpdatePanel 컨트롤의 내용을 새로고침하는 것을 보여줍니다.



그림 1. Partial-page rendering overview

부분 페이지의 업데이트를 가능하게 하기

UpdatePanel 컨트롤은 웹 페이지에서 ScriptManager 컨트롤을 필요로 합니다. 기본적으로, 부분 페이지의 업데이트는 ScriptManager 컨트롤의 EnablePartialRendering 속성이 기본값인 true이기 때문에 가능합니다. 아래의 예제는 페이지에 ScriptManager 컨트롤과 UpdatePanel 컨트롤을 정의하는 것을 보여줍니다. UpdatePanel 컨트롤은 클릭했을 때 패널 안에 있는 내용이 새로고침되는 Button 컨트롤을 포함하고 있습니다. 기본적으로 ChildrenAsTriggers 속성은 true입니다. 그러므로, Button 컨트롤은 비동기 포스트백 컨트롤인 것처럼 행동합니다.

[실행화면]   [소스보기]

UpdatePanel 컨트롤의 컨텐츠를 열거하기

UpdatePanel 선언적인 컨트롤 또는 ContentTemplate 속성을 사용한 디자이너에서 컨텐츠를 추가합니다. 이 속성은 <ContentTemplate> 마크업 태그로써 표현됩니다. 프로그래밍적으로 컨텐츠를 추가하기 위해서는 ContentTemplateContainer 속성을 사용해야 합니다.

하나 또는 그 이상의 UpdatePanel 컨트롤들이 포함된 웹 페이지가 첫번째 렌더링될 때, UpdatePanel의 모든 컨텐츠들은 렌더링되고 브라우저로 보내지게 됩니다. 비동기 포스트백에 이어서, 개별적 UpdatePanel 컨트롤들의 컨텐츠가 업데이트될 것입니다. 포스트백을 유발하는 요소들을 가진 패널의 세팅과 각 패널에 명시된 코드에 의존되어 업데이트 됩니다.

UpdatePanel Triggers 열거하기

기본적으로, UpdatePanel 컨트롤 안에 있는 어떠한 포스트백 컨트롤은 비동기 포스트백을 유발하고 패널의 컨텐츠를 새로고침합니다. 그러나, 또한 UpdatePanel 컨트롤을 새로고침하는 페이지상의 다른 컨트롤들을 구성할 수 있습니다. 그것은 UpdatePanel의 트리거를 정의함으로써 사용할 수 있습니다. 트리거는 패널을 업데이트하기 위해 유발시키는 포스트백 컨트롤과 이벤트를 정의합니다. 트리거 컨트롤의 명시된 이벤트가 발생할 때(예를 들어, Button의 Click 이벤트), 업데이트 패널은 새로고침됩니다.

아래의 예제는 UpdatePanel 컨트롤에서 트리거를 어떻게 정의하는지를 보여줍니다.

[실행화면]   [소스보기]

트리거는 UpdatePanel 컨트롤의 <Triggers> 요소안에 <asp:AsyncPostBackTrigger>로 정의됩니다. (만약, Visual Studio에서 페이지를 수정한다면, UpdatePanelTrigger Collection Editor 대화 상자를 사용하여 트리거를 만들 수 있습니다.)

트리거의 컨트롤 이벤트는 선택적입니다. 만약, 어떠한 이벤트도 명시되지 않으면, 트리거 이벤트는 컨트롤의 기본 이벤트가 됩니다. 예를 들어 Button 컨트롤의 기본 이벤트는 Click 이벤트입니다.

어떻게 UpdatePanel 컨트롤들이 새로고침되는가?

아래의 리스트는 부분 페이지의 렌더링 동안 패널의 컨텐츠가 업데이트 될 때 결정하는 Updatepanel 컨트롤의 속성 설정을 묘사한 것입니다.

  • 만약 UpdateMode 속성이 Always로 설정이 되어 있다면, 페이지의 어디에서나 매번 포스트백을 시작시켜 UpdatePanel 컨트롤의 컨텐츠가 업데이트됩니다. 이것은 다른 UpdatePanel 컨트롤들 안에 있는 컨트롤들에서의 비동기 포스트백과 UpdatePanel 컨트롤의 안에 없는 컨트롤들에서의 비동기 포스트백을 포함합니다.

  • 만약 UpdateMode 속성이 Conditional로 설정이 되어 있다면, UpdatePanel의 컨트롤의 컨텐츠는 아래의 사항 중 하나가 true일 때 업데이트됩니다.
       
  • UpdatePanel 컨트롤의 트리거에 의해 포스트백이 발생될 때
       
  • UpdatePanel 컨트롤의 Update() 메소드를 명시적으로 호출할 때
       
  • UpdatePanel 컨트롤이 다른 UpdatePanel 컨트롤 안으로 중첩되어 부모의 Panel이 업데이트될 때
       
  • ChildrenAsTriggers 속성이 true 이고 UpdatePanel 컨트롤의 어떠한 자식 컨트롤이 포스트백을 유발할 때. 중첩된 UpdatePanel 컨트롤의 자식 컨트롤들은 부모 패널의 트리거에서 명시적으로 정의하지 않는 이상은 UpdatePanel 컨트롤 밖의 업데이트를 유발하지 않습니다.

    만약 ChildrenAsTriggers 속성이 false로 설정되고 UpdateMode 속성이 Always로 설정되면, 예외가 던져집니다. ChildrenAsTriggers 속성은 UpdateMode 속성이 Conditional 로 설정되었을 때만 사용할 수 있습니다.

    마스터 페이지에서 UpdatePanel 컨트롤들을 사용하기

    마스터 페이지에서 UpdatePanel 컨트롤을 사용하기 위해서는 어떻게 ScriptManager 컨트롤을 포함할 것인지를 결정해야 합니다. 만약, 마스터 페이지에 ScriptManager 컨트롤을 포함시킨다면, 모든 컨텐츠 페이지들에 ScriptManager 컨트롤로써 실행될 수 있습니다. (만약 컨텐츠 페이지에서 선언적으로 스크립트들 또는 서비스들을 등록하기를 원한다면, 컨텐츠 페이지에 ScriptManagerProxy 컨트롤을 추가해야 합니다.)

    만약, 마스터 페이지가 ScriptManager 컨트롤을 포함하지 않는다면, UpdatePanel 컨트롤을 포함하는 각 컨텐츠 페이지마다 개별적으로 ScriptManager 컨트롤들을 추가해야 합니다. 이 디자인 선택은 어떻게 응용프로그램에서 클라이언트 스크립트를 관리하는가에 의존되어 있습니다. 어떻게 클라이언트 스크립트를 관리하는지에 대한 더 많은 정보는 ScriptManager Control Overview를 보도록 하십시요. 마스터 페이지에 대한 더 많은 정보는 ASP.NET Master Pages Overview를 보도록 하십시요.

    만약, 마스터 페이지에 ScriptManager 컨트롤이 있고 컨텐츠 페이지의 부분 페이지을 렌더링하는 기능이 필요하지 않는다면, 컨텐츠 페이지에서 프로그래밍적으로 ScriptManager 컨트롤의 EnablePartialRendering 속성을 false로 설정합니다.

    아래의 예제는 마스터 페이지와 컨텐츠 페이지에 있는 ScriptManager 컨트롤의 마크업을 보여줍니다. 이 예제에서, LastUpdate라는 속성은 마스터 페이지에 정의되어 있고, UpdatePanel 컨트롤의 안에서 참조하게 되어 있습니다.

    [실행화면]   [소스보기]

    중첩된 UpdatePanel 컨트롤들을 사용하기

    UpdatePanel 컨트롤들은 중첩될 수 있습니다. 만약 부모 패널이 새로고침된다면, 모든 중첩된 패널들 또한 새로고침됩니다.

    아래의 예제는 다른 UpdatePanel 컨트롤 안에 있는 UpdatePanel 컨트롤이 정의된 마크업을 보여줍니다. 부모 패널 트리거에 있는 Button은 부모와 자식의 패널의 컨텐츠를 업데이트합니다. 자식 패널 트리거에 있는 Button은 단지 자식 패널의 컨텐츠만을 업데이트 합니다.

    [실행화면]   [소스보기]

    아래의 예제는 GridView 컨트롤에서 중첩된 UpdatePanel 컨트롤을 보여줍니다. GridView 컨트롤은 UpdatePanel 컨트롤 안에 있으며, 각 GridView 행은 다른 UpdatePanel 컨트롤 안에 있는 중첩된 GridView 컨트롤을 포함하고 있습니다.

    [실행화면]   [소스보기]

    안쪽의 GridView 컨트롤이 새로운 페이지로 표시될 때, 바깥쪽의 패널과 바깥쪽의 GridView 컨트롤의 다른 행들은 새로고침되지 않습니다. 바깥쪽의 GridView 컨트롤이 새로운 페이지로 표시될 때 바깥쪽의 패널과 중첩된 패널들은 모두 새로고침됩니다.

    프로그래밍적으로 UpdatePanel을 새로고침하기

    아래의 예제는 프로그래밍적으로 UpdatePanel 컨트로을 어떻게 새로고침하는 지를 보여줍니다. 이 예제에서, 페이지는 RegisterAsyncPostBackControl(Control)를 호출하는 트리거로 실행됩니다. 프로그래밍적으로 Update() 메소드를 호출하는 UpdatePanel 컨트롤을 사용하는 이 코드로 페이지를 새로고침할 수 있습니다.

    [실행화면]   [소스보기]

    프로그래밍적으로 UpdatePanel을 만들기

    페이지에 프로그래밍적으로 UpdatePanel 컨트롤을 추가하기 위해서 UpdatePanel 컨트롤의 새로운 인스턴스를 만듭니다. 그리고, ContentTemplateContainer 속성과 Add(Control) 메소드를 사용하여 컨트롤을 추가합니다. 직접 ContentTemplate 속성으로 컨트롤을 추가할 수는 없습니다.

    UpdatePanel 컨트롤이 프로그래밍적으로 추가되었을 때, UpdatePanel 컨트롤이 트리거로써 사용될 수 있는 동일한 이름의 컨테이너에 있는 컨트롤에서만 포스트백됩니다.

    아래의 예제는 어떻게 프로그래밍적으로 페이지에 UpdatePanel 컨트롤을 추가하는지를 보여줍니다. 예제는 ContentTemplateContainer 속성을 사용하여 UpdatePanel 컨트롤로 Label 컨트롤과 Button 컨트롤을 추가합니다. 기본적으로 ChildrenAsTriggers 속성이 true이기 때문에, 패널의 트리거로써 Button 컨트롤이 실행됩니다.

    [실행화면]   [소스보기]

    UpdatePanel 컨트롤과 사용하지 못하는 컨트롤들

    부분 페이지의 업데이트를 사용하지 못하는 ASP.NET 컨트롤들이 있기에 UpdatePanel 컨트롤 안에 사용할 수 없습니다.
  • TreeView와 Menu 컨트롤
  • 웹 파트 컨트롤. 더 많은 정보는 ASP.NET Web Parts Controls를 보도록 하십시요.
  • 비동기 포스트백의 일부분으로써 파일 업로드에 사용되는 FileUpload 컨트롤
  • EnableSortingAndPagingCallbacks 속성이 true로 설정된 GridView와 DetailView 컨트롤. 기본값은 false입니다.
  • 수정할 수 있는 템플릿로 변환할 수 없는 컨텐츠를 가진 Login, PasswordRecovery, ChangePassword, CreateUserWizard 컨트롤들
  • Subsitution 컨트롤
  • BaseCompareValidator, BaseValidator, CompareValidator, CustomValidator, RangeValidator, RegularExpressionValidator, RequiredFieldValidator, ValidationSummary와 같은 Validation 컨트롤들

    부분 페이지의 렌더링과 사용하지 못하는 컨트롤들은 UpdatePanel 컨트롤의 외부에서 사용될 수는 있습니다. 덧붙여서, 몇 가지 경우 부분 페이지의 업데이트와 사용하지 못하는 컨트롤들을 특정한 방법으로 만들어 사용할 수는 있습니다. 예를 들어, 만약 Login, ChangePassword, PasswordRecovery 컨트롤들의 컨텐츠를 템플릿으로 변환할 수 있다면, UpdatePanel 컨트롤의 안에 Login, ChangePassword, PasswordRecovery 컨트롤들을 사용할 수 있습니다. (만약, Visual Studio를 사용한다면 디자인 뷰에서 스마트 메뉴 명령 예를 들면 템플릿으로 변환 등을 사용하여 컨트롤들을 변환할 수 있습니다.) 이 컨트롤들을 수정 가능한 템플릿으로 변환하면, 유효성 컨트롤들은 페이지에서 명시적으로 마크업으로 정의된 컨트롤에서 사용됩니다. UpdatePanel 컨트롤과 사용할 수 있는 유효성을 만들기 위해서, EnableClientScript 속성을 false로 설정합니다. 이것은 브라우저에서 유효성 검사를 수행할 때 일반적으로 사용되는 클라이언트 스크립트에 접근하지 않게 합니다. 그 결과, 비동기 포스트백이 발생하는 동안 유효성은 서버에서 유효성 검사를 수행합니다. 그러나, UpdatePanel의 컨텐츠만이 새로고침되기 때문에, 유효성은 보통 클라이언트 스크립트에 의해 제공되는 직접적인 피드백의 일부분만을 제공할 수 있습니다.

    UpdatePanel 컨트롤 안에서 FileUpload 컨트롤을 사용하기 위해서는, 패널의 PostBackTrigger에 의해 파일을 전송할 수 있도록 포스트백 컨트롤을 설정합니다.

    다른 모든 컨트롤들은 UpdatePanel 컨트롤 안에서 동작합니다. 그러나, 어떠한 상황에서는 컨트롤은 UpdatePanel 컨트롤 안에서의 동작을 기대할 수 없습니다. 이 상황은 다음과 같습니다.

  • ClientScriptManager 컨트롤에 등록된 메소드들을 호출하는 스크립트인 경우
  • Write(String) 메소드를 호출하는 것과 같은 컨트롤의 렌더링동안 직접적으로 스크립트 또는 마크업을 렌더링하는 경우

    만약 컨트롤이 ClientScriptManager 컨트롤에 등록된 메소드의 스크립트를 호출한다면, 대신 ScriptManager 컨트롤에 등록된 메소드의 스크립트에 대한 응답을 사용할 수 있습니다. 이 경우, 컨트롤은 UpdatePanel 컨트롤 안에서 동작할 것입니다.

    코드 예제

    다음은 어떻게 UpdatePanel 컨트롤을 만들고 사용하는지에 대한 예제가 포함된 섹션의 목록입니다.



    클래스 참조

    아래의 테이블에는 UpdatePanel 컨트롤의 주요한 서버 클래스들이 보여집니다.

    클래스

    설명

    UpdatePanel

    부분 페이지 업데이트에 참여할 수 있는 웹 페이지 일부분에 명시된 서버 컨트롤

    ScriptManager

    부분 페이지 렌더링을 관리하는 서버 컨트롤입니다. ScriptManager 컨트롤은 브라우저로 보내기 이한 스크립트 컴포넌트들을 처리합니다. 또한, 페이지가 렌더링될 때 명시된 범위내에서 렌더링하기 위해서 페이지를 오버라이드합니다.

    ScriptManagerProxy

    스크립트와 웹 서비스 참조를 추가하기 위한 중첩된 컴포넌트(예를 들어 컨텐츠 페이지 또는 사용자 컨트롤)들을 가능하게 하는 서버 컨트롤입니다. 이 컨트롤은 만약 부모 요소에 이미 ScriptManager 컨트롤이 포함되어 있다면 유용하게 사용할 수 있습니다.

    PageRequestManager

    브라우저에서 부분 페이지 렌더링에 협조하는 Microsoft AJAX 라이브러리에 있는 클래스입니다. PageRequestManager 클래스는 비동기적으로 서버와 정보를 교환하고 일반적 클라이언트 스크립트 개발을 위한 이벤트와 메소드를 드러내게 합니다.



    포스팅을 마치며... ----------------------------------------------------------------------------
    아, 역시 아무리 생각해도 번역은 OTL


  • articles
    recent replies
    recent trackbacks
    notice
    Admin : New post