İzlenecek yol: IQueryable LINQ sağlayıcısı oluşturma

Bu gelişmiş konu özel oluşturmak için adım adım yönergeler sağlar LINQ sağlayıcı. İşlemi tamamladığınızda, yazmak için oluşturma sağlayıcısı kullanmak mümkün olacaktır LINQ usa TerraServer Web hizmetini sorgular.

Türkiye TerraServer Web hizmeti ABD'nin hava görüntülerinin bir veritabanı için bir arabirim sağlar.Ayrıca, Amerika Birleşik Devletleri'nde belirli bir kısmını veya tamamını konum adı konumları hakkında bilgi döndüren bir yöntem sunar.Olarak adlandırılan bu yöntem GetPlaceList, yöntem, sizin LINQ sağlayıcı çağıracaktır. Sağlayıcının kullanacağı Windows Communication Foundation (WCF) Web hizmeti ile iletişim kurmak için.Türkiye TerraServer Web hizmeti hakkında daha fazla bilgi için bkz: usa TerraServer Web hizmetlerine genel bakış.

Bu sağlayıcı oldukça basit olduğunu IQueryable sağlayıcı.Belirli bilgileri işleme sorguları bekler ve sonuç verileri göstermek için tek bir tür ortaya çıkarma bir kapalı tür sistemi vardır.Bu sağlayıcı yalnızca bir tür yöntem çağrısı en içteki çağrı sorguyu temsil eden bir ifade ağacı ifadesinde inceler Where.Bu Web hizmeti bu ifadeden sorgulamak için gereken verileri ayıklar.Daha sonra Web servisini ve döndürülen verileri ifade ağacını ilk kutu ekler IQueryable veri kaynağı.Sorgu yürütme geri kalanı tarafından ele Enumerable uygulamalarında standart sorgu işleçler.

Bu konuda kod örnekleri C# [NULL]'ta sağlanır ve Visual Basic.

Bu örneklerde aşağıdaki görevler gösterilir:

  • Proje oluşturma Visual Studio.

  • İçin gerekli arabirimleri uygulayan bir IQueryableLINQ sağlayıcı: IQueryable<T>, IOrderedQueryable<T>, ve IQueryProvider.

  • Web hizmetinden veri göstermek için özel bir .NET türü ekleme.

  • Bir sorgu içeriği ve Web hizmetinden veri alan bir sınıfı oluşturma.

  • Bir ifade ağacı ziyaretçisi alt sınıfı oluşturma çağrısı en içteki temsil eden ifade bulur Queryable.Where yöntem.

  • Bir ifade ağacı ziyaretçisi alt sınıfı oluşturma bilgilerini ayıklar LINQ Web hizmeti isteği içinde kullanmak için sorgu.

  • Tam temsil eden bir ifade ağacı değiştiren bir ifade ağacı ziyaretçisi alt sınıfı oluşturma LINQ sorgu.

  • Bir ifade ağacı kısmen değerlendirmek için bir değerlendirme sınıfını kullanarak.Tüm yerel değişken başvuruları çeviren Bu adım gereklidir, çünkü LINQ sorguda değerleri birleştirir.

  • Bir ifade ağacı yardımcı ve yeni bir özel durum sınıfı oluşturma.

  • Test LINQ sağlayıcı içeren bir istemci uygulamasından bir LINQ sorgu.

  • Daha karmaşık sorgu yetenekleri için ekleme LINQ sağlayıcı.

    [!NOT]

    Bu izlenecek yolda oluşturur LINQ sağlayıcı bir örnek olarak kullanılabilir.Daha fazla bilgi için bkz. LINQ Örnekleri.

Önkoşullar

Bu izlenecek yolda, sunulan özellikleri gerektirir Visual Studio 2008.

[!NOT]

Bilgisayarınızda, aşağıdaki yönergelerde yer alan Visual Studio kullanıcı arabirimi öğelerinden bazılarının adı veya konumu farklı gösterilebilir. Bu öğeleri bilgisayarınızdaki Visual Studio sürümü ve kullandığınız ayarlar belirler. Daha fazla bilgi için bkz: Visual Studio ayarları.

Projeyi Oluşturma

Visual Studio'da proje oluşturmak için

  1. İçinde Visual Studio, yeni bir Class Library uygulama. Proje adı LinqToTerraServerProvider.

  2. İçinde Çözüm Gezgini, select Class1.cs (veya Class1.vb'ye) için yeniden adlandırın ve dosya QueryableTerraServerData.cs (veya QueryableTerraServerData.vb).Açılan iletişim kutusunda tıklatın Evet kod öğesi için tüm başvuruları yeniden adlandırma.

    Sağlayıcı olarak oluşturduğunuz bir Sınıf kitaplığı da proje Visual Studio çünkü yürütülebilir istemci uygulamaları kendi proje başvurusu olarak sağlayıcı derlemesi ekleyeceksiniz.

Web hizmetinin hizmet başvuru eklemek için

  1. İçinde Çözüm Gezgini, sağ LinqToTerraServerProvider 'ı tıklatın ve proje Hizmet Başvuru Ekle.

    Hizmet Başvuru Ekle iletişim kutusunu açar.

  2. İçinde Adres yazın http://terraserver.microsoft.com/TerraService2.asmx.

  3. İçinde ad yazın TerraServerReference ve ardından Tamam.

    Uygulama tarafından yolu, Web hizmeti ile iletişim kurabilmesi usa TerraServer Web hizmetinin hizmet başvuru olarak eklenir Windows Communication Foundation (WCF).Proje hizmeti başvuru ekleyerek Visual Studio oluşturduğu bir app.config bir proxy ve Web hizmeti için bir son nokta içeren dosya.Daha fazla bilgi için bkz. Windows Communication Foundation hizmetlerini ve Visual Studio wcf Veri Hizmetleri.

Şimdi adlı bir dosya olan bir proje olan app.config, adlı bir dosya QueryableTerraServerData.cs (veya QueryableTerraServerData.vb) ve adlı bir hizmet başvuru TerraServerReference.

Gerekli arabirimleri uygulayan

Oluşturmak için bir LINQ en azından gerekir uygulamak sağlayıcı IQueryable<T> ve IQueryProvider arabirimleri. IQueryable<T>ve IQueryProvider diğer gerekli arabirimlerden; türetilmiş Bu nedenle, bu iki arabirimleri uygulayarak, ayrıca için gerekli arabirimleri uygulayan bir LINQ sağlayıcı.

Sıralama sorgu işleçleri gibi desteklemek istiyorsanız OrderBy ve ThenBy, ayrıca uygulamalıdır IOrderedQueryable<T> arabirim.Çünkü IOrderedQueryable<T> türetilen IQueryable<T>, bu sağlayıcı yaptığı bir türü, bu arabirimlerin her ikisini uygulayabilirsiniz.

System.Linq.IQueryable'1 ve System.Linq.IOrderedQueryable'1 uygulamak için

  • Dosya QueryableTerraServerData.cs (veya QueryableTerraServerData.vb), aşağıdaki kodu ekleyin.

    Imports System.Linq.Expressions
    
    Public Class QueryableTerraServerData(Of TData)
        Implements IOrderedQueryable(Of TData)
    
    #Region "Private members"
    
        Private _provider As TerraServerQueryProvider
        Private _expression As Expression
    
    #End Region
    
    #Region "Constructors"
    
        ''' <summary>
        ''' This constructor is called by the client to create the data source.
        ''' </summary>
        Public Sub New()
            Me._provider = New TerraServerQueryProvider()
            Me._expression = Expression.Constant(Me)
        End Sub
    
        ''' <summary>
        ''' This constructor is called by Provider.CreateQuery().
        ''' </summary>
        ''' <param name="_expression"></param>
        Public Sub New(ByVal _provider As TerraServerQueryProvider, ByVal _expression As Expression)
    
            If _provider Is Nothing Then
                Throw New ArgumentNullException("provider")
            End If
    
            If _expression Is Nothing Then
                Throw New ArgumentNullException("expression")
            End If
    
            If Not GetType(IQueryable(Of TData)).IsAssignableFrom(_expression.Type) Then
                Throw New ArgumentOutOfRangeException("expression")
            End If
    
            Me._provider = _provider
            Me._expression = _expression
        End Sub
    
    #End Region
    
    #Region "Properties"
    
        Public ReadOnly Property ElementType(
            ) As Type Implements IQueryable(Of TData).ElementType
    
            Get
                Return GetType(TData)
            End Get
        End Property
    
        Public ReadOnly Property Expression(
            ) As Expression Implements IQueryable(Of TData).Expression
    
            Get
                Return _expression
            End Get
        End Property
    
        Public ReadOnly Property Provider(
            ) As IQueryProvider Implements IQueryable(Of TData).Provider
    
            Get
                Return _provider
            End Get
        End Property
    
    #End Region
    
    #Region "Enumerators"
    
        Public Function GetGenericEnumerator(
            ) As IEnumerator(Of TData) Implements IEnumerable(Of TData).GetEnumerator
    
            Return (Me.Provider.
                    Execute(Of IEnumerable(Of TData))(Me._expression)).GetEnumerator()
        End Function
    
        Public Function GetEnumerator(
            ) As IEnumerator Implements IEnumerable.GetEnumerator
    
            Return (Me.Provider.
                    Execute(Of IEnumerable)(Me._expression)).GetEnumerator()
        End Function
    
    #End Region
    
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    
    namespace LinqToTerraServerProvider
    {
        public class QueryableTerraServerData<TData> : IOrderedQueryable<TData>
        {
            #region Constructors
            /// <summary>
            /// This constructor is called by the client to create the data source.
            /// </summary>
            public QueryableTerraServerData()
            {
                Provider = new TerraServerQueryProvider();
                Expression = Expression.Constant(this);
            }
    
            /// <summary>
            /// This constructor is called by Provider.CreateQuery().
            /// </summary>
            /// <param name="expression"></param>
            public QueryableTerraServerData(TerraServerQueryProvider provider, Expression expression)
            {
                if (provider == null)
                {
                    throw new ArgumentNullException("provider");
                }
    
                if (expression == null)
                {
                    throw new ArgumentNullException("expression");
                }
    
                if (!typeof(IQueryable<TData>).IsAssignableFrom(expression.Type))
                {
                    throw new ArgumentOutOfRangeException("expression");
                }
    
                Provider = provider;
                Expression = expression;
            }
            #endregion
    
            #region Properties
    
            public IQueryProvider Provider { get; private set; }
            public Expression Expression { get; private set; }
    
            public Type ElementType
            {
                get { return typeof(TData); }
            }
    
            #endregion
    
            #region Enumerators
            public IEnumerator<TData> GetEnumerator()
            {
                return (Provider.Execute<IEnumerable<TData>>(Expression)).GetEnumerator();
            }
    
            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return (Provider.Execute<System.Collections.IEnumerable>(Expression)).GetEnumerator();
            }
            #endregion
        }
    }
    

    IOrderedQueryable<T> Uygulaması tarafından QueryableTerraServerData bildirilen üç özellik sınıfını uygulayan IQueryable ve iki numaralandırma yöntemleri de IEnumerable ve IEnumerable<T>.

    Bu sınıf iki oluşturucusu yok.Yazmak için bir nesne oluşturmak için istemci uygulamasını ilk kurucusu çağrılır LINQ karşı sorgu.Kurucu kod tarafından iç sağlayıcısı kitaplığı denir IQueryProvider uygulaması.

    Zaman GetEnumerator türünde bir nesne yöntemi çağrıldığında QueryableTerraServerData, onu gösteren sorgu yürütülür ve sorgu sonuçlarını numaralandırılır.

    Sınıfın adı dışında bu kod bu usa TerraServer Web servis sağlayıcıya özgü değildir.Bu nedenle, bunun için yeniden kullanılabilir LINQ sağlayıcı.

System.Linq.IQueryProvider uygulamak için

  • Ekleme TerraServerQueryProvider sınıf projenize.

    Imports System.Linq.Expressions
    Imports System.Reflection
    
    Public Class TerraServerQueryProvider
        Implements IQueryProvider
    
        Public Function CreateQuery(
            ByVal expression As Expression
            ) As IQueryable Implements IQueryProvider.CreateQuery
    
            Dim elementType As Type = TypeSystem.GetElementType(expression.Type)
    
            Try
                Dim qType = GetType(QueryableTerraServerData(Of )).MakeGenericType(elementType)
                Dim args = New Object() {Me, expression}
                Dim instance = Activator.CreateInstance(qType, args)
    
                Return CType(instance, IQueryable)
            Catch tie As TargetInvocationException
                Throw tie.InnerException
            End Try
        End Function
    
        ' Queryable's collection-returning standard query operators call this method.
        Public Function CreateQuery(Of TResult)(
            ByVal expression As Expression
            ) As IQueryable(Of TResult) Implements IQueryProvider.CreateQuery
    
            Return New QueryableTerraServerData(Of TResult)(Me, expression)
        End Function
    
        Public Function Execute(
            ByVal expression As Expression
            ) As Object Implements IQueryProvider.Execute
    
            Return TerraServerQueryContext.Execute(expression, False)
        End Function
    
        ' Queryable's "single value" standard query operators call this method.
        ' It is also called from QueryableTerraServerData.GetEnumerator().
        Public Function Execute(Of TResult)(
            ByVal expression As Expression
            ) As TResult Implements IQueryProvider.Execute
    
            Dim IsEnumerable As Boolean = (GetType(TResult).Name = "IEnumerable`1")
    
            Dim result = TerraServerQueryContext.Execute(expression, IsEnumerable)
            Return CType(result, TResult)
        End Function
    End Class
    
    using System;
    using System.Linq;
    using System.Linq.Expressions;
    
    namespace LinqToTerraServerProvider
    {
        public class TerraServerQueryProvider : IQueryProvider
        {
            public IQueryable CreateQuery(Expression expression)
            {
                Type elementType = TypeSystem.GetElementType(expression.Type);
                try
                {
                    return (IQueryable)Activator.CreateInstance(typeof(QueryableTerraServerData<>).MakeGenericType(elementType), new object[] { this, expression });
                }
                catch (System.Reflection.TargetInvocationException tie)
                {
                    throw tie.InnerException;
                }
            }
    
            // Queryable's collection-returning standard query operators call this method.
            public IQueryable<TResult> CreateQuery<TResult>(Expression expression)
            {
                return new QueryableTerraServerData<TResult>(this, expression);
            }
    
            public object Execute(Expression expression)
            {
                return TerraServerQueryContext.Execute(expression, false);
            }
    
            // Queryable's "single value" standard query operators call this method.
            // It is also called from QueryableTerraServerData.GetEnumerator().
            public TResult Execute<TResult>(Expression expression)
            {
                bool IsEnumerable = (typeof(TResult).Name == "IEnumerable`1");
    
                return (TResult)TerraServerQueryContext.Execute(expression, IsEnumerable);
            }
        }
    }
    

    Bu sınıf sorgu sağlayıcı kodunda uygulamak için gereken dört yöntemleri uygulayan IQueryProvider arabirim.İki CreateQuery yöntemleri, veri kaynağıyla ilişkili sorgular oluşturma.İki Execute yöntemleri gönderme gibi sorguları yürütülecek.

    Genel olmayan CreateQuery yöntemi yansıtma oluşturduğu sorgu yürütülmekte döndüren dizi öğe türü elde etmek için kullanır.Daha sonra kullanır Activator yeni bir oluşturmak için sınıf QueryableTerraServerData öğe türü genel tür bağımsız olarak oluşturulmuş örnek.Genel olmayan arama sonucu CreateQuery yöntemi aynı olduğu gibi genel CreateQuery yöntemi, doğru tür bağımsız değişkeni ile adlandırılan.

    Sorgu yürütme mantığı çoğu daha sonra ekleyeceksiniz farklı bir sınıfa gerçekleştirilir.Kod, bu sınıf için herhangi bir genel dır, sorgulanan, veri kaynağına özgü olduğu için bu işlevi başka bir yerde ele alınır LINQ sağlayıcı.Bu kodu için farklı bir sağlayıcı kullanmak için sınıf adını ve iki yöntem başvurulan sorgu içerik türünün adını değiştirmeniz gerekebilir.

Sonuç verileri göstermek için özel bir türü ekleme

Web hizmetinden alınan verileri göstermek için .NET türü gerekir.Bu tür istemci uygulamasında kullanılacak LINQ istediği sonuçları tanımlamak için sorgu.Aşağıdaki yordam, bir tür oluşturur. Adlı bu tür Place, bir şehir, bir park veya bir lake gibi tek bir coğrafi konum hakkında bilgi içerir.

Bu kod adlı bir numaralandırma türü de içeren PlaceType, çeşitli coğrafi konumunu tanımlar ve kullanılan Place sınıf.

Özel sonuç türü oluşturmak için

  • Ekleme Place sınıfı ve PlaceType projeniz için numaralandırma.

    Public Class Place
        ' Properties.
        Public Property Name As String
        Public Property State As String
        Public Property PlaceType As PlaceType
    
        ' Constructor.
        Friend Sub New(ByVal name As String, 
                       ByVal state As String, 
                       ByVal placeType As TerraServerReference.PlaceType)
    
            Me.Name = name
            Me.State = state
            Me.PlaceType = CType(placeType, PlaceType)
        End Sub
    End Class
    
    Public Enum PlaceType
        Unknown
        AirRailStation
        BayGulf
        CapePeninsula
        CityTown
        HillMountain
        Island
        Lake
        OtherLandFeature
        OtherWaterFeature
        ParkBeach
        PointOfInterest
        River
    End Enum
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace LinqToTerraServerProvider
    {
        public class Place
        {
            // Properties.
            public string Name { get; private set; }
            public string State { get; private set; }
            public PlaceType PlaceType { get; private set; }
    
            // Constructor.
            internal Place(string name,
                            string state,
                            LinqToTerraServerProvider.TerraServerReference.PlaceType placeType)
            {
                Name = name;
                State = state;
                PlaceType = (PlaceType)placeType;
            }
        }
    
        public enum PlaceType
        {
            Unknown,
            AirRailStation,
            BayGulf,
            CapePeninsula,
            CityTown,
            HillMountain,
            Island,
            Lake,
            OtherLandFeature,
            OtherWaterFeature,
            ParkBeach,
            PointOfInterest,
            River
        }
    }
    

    Kurucusu Place türü Web hizmeti tarafından döndürülen türü sonuç nesnesi oluşturma kolaylaştırır.Sağlayıcı Web hizmeti API tarafından doğrudan tanımlanmış sonuç türü döndürürken, istemci uygulamaları, Web hizmeti için bir başvuru eklemek için gerektirecektir.Sağlayıcısı Kitaplığı'nın bir parçası olarak yeni bir tür oluşturarak, istemci türü ve Web hizmeti sunan yöntemleri hakkında bilmek yok.

Veri kaynağından veri almak için işlevsellik ekleme

Bu sağlayıcı uygulaması varsayar en içteki çağrısı Queryable.Where Web hizmetini sorgulamakta kullanılacak konum bilgileri içerir.Tıklatılır Queryable.Where çağrısı where yan tümcesi (Where yan tümcesinde Visual Basic) veya Queryable.Where oluşan ilk yöntem çağrısı bir LINQ sorgu ya da sorguyu temsil eden bir ifade ağacı "altındaki" en yakın olanı.

Sorgu bağlamı sınıfı oluşturmak için

  • Ekleme TerraServerQueryContext sınıf projenize.

    Imports System.Linq.Expressions
    
    Public Class TerraServerQueryContext
    
        ' Executes the expression tree that is passed to it.
        Friend Shared Function Execute(ByVal expr As Expression, 
                                       ByVal IsEnumerable As Boolean) As Object
    
            ' The expression must represent a query over the data source.
            If Not IsQueryOverDataSource(expr) Then
                Throw New InvalidProgramException("No query over the data source was specified.")
            End If
    
            ' Find the call to Where() and get the lambda expression predicate.
            Dim whereFinder As New InnermostWhereFinder()
            Dim whereExpression As MethodCallExpression = 
                whereFinder.GetInnermostWhere(expr)
            Dim lambdaExpr As LambdaExpression
            lambdaExpr = CType(CType(whereExpression.Arguments(1), UnaryExpression).Operand, LambdaExpression)
    
            ' Send the lambda expression through the partial evaluator.
            lambdaExpr = CType(Evaluator.PartialEval(lambdaExpr), LambdaExpression)
    
            ' Get the place name(s) to query the Web service with.
            Dim lf As New LocationFinder(lambdaExpr.Body)
            Dim locations As List(Of String) = lf.Locations
            If locations.Count = 0 Then
                Dim s = "You must specify at least one place name in your query."
                Throw New InvalidQueryException(s)
            End If
    
            ' Call the Web service and get the results.
            Dim places() = WebServiceHelper.GetPlacesFromTerraServer(locations)
    
            ' Copy the IEnumerable places to an IQueryable.
            Dim queryablePlaces = places.AsQueryable()
    
            ' Copy the expression tree that was passed in, changing only the first
            ' argument of the innermost MethodCallExpression.
            Dim treeCopier As New ExpressionTreeModifier(queryablePlaces)
            Dim newExpressionTree = treeCopier.Visit(expr)
    
            ' This step creates an IQueryable that executes by replacing 
            ' Queryable methods with Enumerable methods.
            If (IsEnumerable) Then
                Return queryablePlaces.Provider.CreateQuery(newExpressionTree)
            Else
                Return queryablePlaces.Provider.Execute(newExpressionTree)
            End If
        End Function
    
        Private Shared Function IsQueryOverDataSource(ByVal expression As Expression) As Boolean
            ' If expression represents an unqueried IQueryable data source instance,
            ' expression is of type ConstantExpression, not MethodCallExpression.
            Return (TypeOf expression Is MethodCallExpression)
        End Function
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    
    namespace LinqToTerraServerProvider
    {
        class TerraServerQueryContext
        {
            // Executes the expression tree that is passed to it.
            internal static object Execute(Expression expression, bool IsEnumerable)
            {
                // The expression must represent a query over the data source.
                if (!IsQueryOverDataSource(expression))
                    throw new InvalidProgramException("No query over the data source was specified.");
    
                // Find the call to Where() and get the lambda expression predicate.
                InnermostWhereFinder whereFinder = new InnermostWhereFinder();
                MethodCallExpression whereExpression = whereFinder.GetInnermostWhere(expression);
                LambdaExpression lambdaExpression = (LambdaExpression)((UnaryExpression)(whereExpression.Arguments[1])).Operand;
    
                // Send the lambda expression through the partial evaluator.
                lambdaExpression = (LambdaExpression)Evaluator.PartialEval(lambdaExpression);
    
                // Get the place name(s) to query the Web service with.
                LocationFinder lf = new LocationFinder(lambdaExpression.Body);
                List<string> locations = lf.Locations;
                if (locations.Count == 0)
                    throw new InvalidQueryException("You must specify at least one place name in your query.");
    
                // Call the Web service and get the results.
                Place[] places = WebServiceHelper.GetPlacesFromTerraServer(locations);
    
                // Copy the IEnumerable places to an IQueryable.
                IQueryable<Place> queryablePlaces = places.AsQueryable<Place>();
    
                // Copy the expression tree that was passed in, changing only the first
                // argument of the innermost MethodCallExpression.
                ExpressionTreeModifier treeCopier = new ExpressionTreeModifier(queryablePlaces);
                Expression newExpressionTree = treeCopier.Visit(expression);
    
                // This step creates an IQueryable that executes by replacing Queryable methods with Enumerable methods.
                if (IsEnumerable)
                    return queryablePlaces.Provider.CreateQuery(newExpressionTree);
                else
                    return queryablePlaces.Provider.Execute(newExpressionTree);
            }
    
            private static bool IsQueryOverDataSource(Expression expression)
            {
                // If expression represents an unqueried IQueryable data source instance,
                // expression is of type ConstantExpression, not MethodCallExpression.
                return (expression is MethodCallExpression);
            }
        }
    }
    

    Bu sınıf, bir sorgu yürütme iş düzenler.Tıklatılır temsil eden ifade bulma sonra Queryable.Where çağrısı, bu kod için geçirilen karşılaştırma temsil eden lambda ifadesi alır Queryable.Where.Yerel değişkenler için tüm başvurular değerlere çevrilir, sonra kısmen değerlendirilmesi için bir yöntem doðrulama deyimi geçirir.Sonra istenen konumları karşılaştırma ayıklamak için bir metod çağırır ve sonucu verileri Web hizmetinden elde etmek için başka bir yöntemi çağırır.

    Bir sonraki adımda bu kodunu temsil eden bir ifade ağacı kopyalar LINQ sorgulama ve ifade ağacını bir değişiklik yapar.En içteki sorgu işleci çağrı uygulandığı veri kaynağı ile somut listesini değiştirmek için bir ifade ağacı ziyaretçisi alt sınıf kodu kullanır Place Web hizmetinden edinilmiş nesneler.

    Önce listesini Place türü değiştirilirse, nesneleri deyim ağacına eklenen IEnumerable için IQueryable çağırarak AsQueryable.Bu tür değişikliği gerekli çünkü ifade ağacını yeniden yazan, en içteki sorgu işleci yöntemi için yöntem çağrısı gösteren düğümü yeniden düzenlenir.Bağımsız değişkenlerden biri değiştiği için düğümü yeniden yapılandırılmış (yani, uygulanmış veri kaynağı).Call(Expression, MethodInfo, IEnumerable<Expression>) Düğümü yeniden oluşturmak için kullanılan yöntem, bir özel durum herhangi bir bağımsız değişken için geçirilecek yöntemin ilgili parametre atanabilir değilse.Bu durumda, IEnumerable listesini Place nesneler değil için atanabilir olurdu IQueryable parametresi Queryable.Where.Bu nedenle, onun türü değiştirildi IQueryable.

    Kendi türünü değiştirerek IQueryable, ayrıca koleksiyon alır bir IQueryProvider üye tarafından erişilen, Provider oluşturabilir veya sorguları yürütme özelliği,.Dinamik türde IQueryable°Place koleksiyonu EnumerableQuery, türü için iç System.Linq API.Bu türü ile ilişkilendirilmiş sorgu sağlayıcısı değiştirerek sorguları yürütür Queryable standart sorgu işleci ile eşdeğer çağırır Enumerable işleçler, verimli şekilde, sorgu olur bir LINQ nesneleri sorgulamak.

    Son kod, TerraServerQueryContext sınıfı üzerinde iki yöntemden birini çağırır IQueryable listesini Place nesneler.Çağırdığı CreateQuery istemci sorgu sýralanabilir sonuçları ise veya Execute istemci sorgu sýralanabilir olmayan bir sonuç döndürürse.

    Bu sınıftaki kodu çok bu TerraServer usa sağlayıcıya özeldir.Bu nedenle, içinde kapsüllenir TerraServerQueryContext yerine doğrudan daha fazla genel eklenmekte sınıfı IQueryProvider uygulaması.

Bilgileri yalnızca oluşturmakta sağlayıcı gerektirir Queryable.Where Web hizmetini sorgulamakta karşılaştırma. bu nedenle, kullandığı LINQ nesneleri yürütme iş yapmak için LINQ iç kullanarak sorgu EnumerableQuery türü.Kullanmak için alternatif bir yol LINQ yürütülecek nesneleri için sorgu tarafından yürütülecek sorgunun parçası Kaydır istemci sağlamaktır LINQ nesnelere bir LINQ nesneleri sorgulamak.Bu arama yoluyla yapılır AsEnumerable<TSource> sorgu kalan olduğu sağlayıcı gerektirir, belirli amaçlar için sorgu parçası.Avantajı, bu tür bir uygulama özel sağlayıcı arasındaki iş bölümü olan ve LINQ nesnelere daha açıktır.

[!NOT]

Bu konuda sunulan kendi minimum sorgu desteği olan basit bir sağlayıcı sağlayıcısıdır.Bu nedenle, yoğun olarak üzerinde dayanır LINQ nesnelere sorguları yürütmek için.Karmaşık bir LINQ sağlayıcı gibi LINQ to SQL tüm sorgu herhangi bir iş kapatmak için etme olmadan destekleyebilir LINQ nesneler.

Web hizmetinden veri almak için bir sınıf oluşturmak için

  • Ekleme WebServiceHelper sınıf (veya modülü Visual Basic) projenize.

    Imports System.Collections.Generic
    Imports LinqToTerraServerProvider.TerraServerReference
    
    Friend Module WebServiceHelper
        Private numResults As Integer = 200
        Private mustHaveImage As Boolean = False
    
        Friend Function GetPlacesFromTerraServer(ByVal locations As List(Of String)) As Place()
            ' Limit the total number of Web service calls.
            If locations.Count > 5 Then
                Dim s = "This query requires more than five separate calls to the Web service. Please decrease the number of places."
                Throw New InvalidQueryException(s)
            End If
    
            Dim allPlaces As New List(Of Place)
    
            ' For each location, call the Web service method to get data.
            For Each location In locations
                Dim places = CallGetPlaceListMethod(location)
                allPlaces.AddRange(places)
            Next
    
            Return allPlaces.ToArray()
        End Function
    
        Private Function CallGetPlaceListMethod(ByVal location As String) As Place()
    
            Dim client As New TerraServiceSoapClient()
            Dim placeFacts() As PlaceFacts
    
            Try
                ' Call the Web service method "GetPlaceList".
                placeFacts = client.GetPlaceList(location, numResults, mustHaveImage)
    
                ' If we get exactly 'numResults' results, they are probably truncated.
                If (placeFacts.Length = numResults) Then
                    Dim s = "The results have been truncated by the Web service and would not be complete. Please try a different query."
                    Throw New Exception(s)
                End If
    
                ' Create Place objects from the PlaceFacts objects returned by the Web service.
                Dim places(placeFacts.Length - 1) As Place
                For i = 0 To placeFacts.Length - 1
                    places(i) = New Place(placeFacts(i).Place.City, 
                                          placeFacts(i).Place.State, 
                                          placeFacts(i).PlaceTypeId)
                Next
    
                ' Close the WCF client.
                client.Close()
    
                Return places
            Catch timeoutException As TimeoutException
                client.Abort()
                Throw
            Catch communicationException As System.ServiceModel.CommunicationException
                client.Abort()
                Throw
            End Try
        End Function
    End Module
    
    using System;
    using System.Collections.Generic;
    using LinqToTerraServerProvider.TerraServerReference;
    
    namespace LinqToTerraServerProvider
    {
        internal static class WebServiceHelper
        {
            private static int numResults = 200;
            private static bool mustHaveImage = false;
    
            internal static Place[] GetPlacesFromTerraServer(List<string> locations)
            {
                // Limit the total number of Web service calls.
                if (locations.Count > 5)
                    throw new InvalidQueryException("This query requires more than five separate calls to the Web service. Please decrease the number of locations in your query.");
    
                List<Place> allPlaces = new List<Place>();
    
                // For each location, call the Web service method to get data.
                foreach (string location in locations)
                {
                    Place[] places = CallGetPlaceListMethod(location);
                    allPlaces.AddRange(places);
                }
    
                return allPlaces.ToArray();
            }
    
            private static Place[] CallGetPlaceListMethod(string location)
            {
                TerraServiceSoapClient client = new TerraServiceSoapClient();
                PlaceFacts[] placeFacts = null;
    
                try
                {
                    // Call the Web service method "GetPlaceList".
                    placeFacts = client.GetPlaceList(location, numResults, mustHaveImage);
    
                    // If there are exactly 'numResults' results, they are probably truncated.
                    if (placeFacts.Length == numResults)
                        throw new Exception("The results have been truncated by the Web service and would not be complete. Please try a different query.");
    
                    // Create Place objects from the PlaceFacts objects returned by the Web service.
                    Place[] places = new Place[placeFacts.Length];
                    for (int i = 0; i < placeFacts.Length; i++)
                    {
                        places[i] = new Place(
                            placeFacts[i].Place.City,
                            placeFacts[i].Place.State,
                            placeFacts[i].PlaceTypeId);
                    }
    
                    // Close the WCF client.
                    client.Close();
    
                    return places;
                }
                catch (TimeoutException timeoutException)
                {
                    client.Abort();
                    throw;
                }
                catch (System.ServiceModel.CommunicationException communicationException)
                {
                    client.Abort();
                    throw;
                }
            }
        }
    }
    

    Bu sınıf Web hizmetinden veri alır işlevselliği içerir.Bu kod adlı kullanır TerraServiceSoapClient, otomatik olarak proje tarafından üretilen Windows Communication Foundation (WCF), Web servis yöntemi çağırın GetPlaceList.Daha sonra her sonuç için veri sağlayıcısı tanımlar .NET türü Web hizmeti yöntemi dönüş türünden çevrilir.

    Bu kodu sağlayıcısı kitaplığı kullanılabilirliğini geliştiren iki denetimleri içerir.İlk onay beş sorguyu her Web hizmeti için yapılan çağrıları toplam sayısını sınırlayarak bir istemci uygulaması için yanıt bekleyeceği en uzun süreyi sınırlar.İstemci sorguda belirtilen her konum için bir Web hizmeti isteği oluşturulur.Bu nedenle, beşten fazla konumları sorgu içeriyorsa, sağlayıcı bir istisna atar.

    İkinci onay Web hizmeti tarafından döndürülen sonuç sayısı dönmek sonuçları en fazla sayıya eşit olup olmadığını belirler.En fazla sonuç sayısı ise, Web hizmetinden alınan sonuçlar kesilir olasıdır.Tamamlanmamış bir listesini istemciye döndürmek yerine, sağlayıcı bir istisna atar.

İfade ağaç ziyaretçi sınıfları ekleme

Burada ifade yöntemini çağırın tıklatılır bulur ziyaretçi oluşturmak için

  1. Ekleme InnermostWhereFinder devralan bir sınıf, ExpressionVisitor projeniz için sınıf.

    Imports System.Linq.Expressions
    
    Class InnermostWhereFinder
        Inherits ExpressionVisitor
    
        Private innermostWhereExpression As MethodCallExpression
    
        Public Function GetInnermostWhere(ByVal expr As Expression) As MethodCallExpression
            Me.Visit(expr)
            Return innermostWhereExpression
        End Function
    
        Protected Overrides Function VisitMethodCall(ByVal expr As MethodCallExpression) As Expression
            If expr.Method.Name = "Where" Then
                innermostWhereExpression = expr
            End If
    
            Me.Visit(expr.Arguments(0))
    
            Return expr
        End Function
    End Class
    
    using System;
    using System.Linq.Expressions;
    
    namespace LinqToTerraServerProvider
    {
        internal class InnermostWhereFinder : ExpressionVisitor
        {
            private MethodCallExpression innermostWhereExpression;
    
            public MethodCallExpression GetInnermostWhere(Expression expression)
            {
                Visit(expression);
                return innermostWhereExpression;
            }
    
            protected override Expression VisitMethodCall(MethodCallExpression expression)
            {
                if (expression.Method.Name == "Where")
                    innermostWhereExpression = expression;
    
                Visit(expression.Arguments[0]);
    
                return expression;
            }
        }
    }
    

    Bu sınıf, belirli bir ifade bulma işlevleri gerçekleştirmek için temel ifade ağaç ziyaretçi sınıf devralır.Temel ifade ağaç ziyaretçi sınıfı miras ve özelleştirilmiş bir ifade ağacı tersine çevirme ile ilgili belirli bir görev için tasarlanmıştır.Türetilmiş bir sınıf geçersiz kılmaları VisitMethodCall en içteki çağrısı temsil eden ifade dışarı arama yöntemi Where ifadesi ağacındaki istemci sorgu temsil eder.Sağlayıcı arama konumları ayıklar ifade bu en içteki ifadesidir.

  2. Ekleme using yönergesi (Imports Visual Basic deyimleri) dosyasına aşağıdaki isim uzayları: System.Collections.Generic, System.Collections.ObjectModel ve System.Linq.Expressions.

Web hizmetini sorgulamakta verileri ayıklar ziyaretçi oluşturmak için

  • Ekleme LocationFinder sınıf projenize.

    Imports System.Linq.Expressions
    Imports ETH = LinqToTerraServerProvider.ExpressionTreeHelpers
    
    Friend Class LocationFinder
        Inherits ExpressionVisitor
    
        Private _expression As Expression
        Private _locations As List(Of String)
    
        Public Sub New(ByVal exp As Expression)
            Me._expression = exp
        End Sub
    
        Public ReadOnly Property Locations() As List(Of String)
            Get
                If _locations Is Nothing Then
                    _locations = New List(Of String)()
                    Me.Visit(Me._expression)
                End If
                Return Me._locations
            End Get
        End Property
    
        Protected Overrides Function VisitBinary(ByVal be As BinaryExpression) As Expression
            ' Handles Visual Basic String semantics.
            be = ETH.ConvertVBStringCompare(be)
    
            If be.NodeType = ExpressionType.Equal Then
                If (ETH.IsMemberEqualsValueExpression(be, GetType(Place), "Name")) Then
                    _locations.Add(ETH.GetValueFromEqualsExpression(be, GetType(Place), "Name"))
                    Return be
                ElseIf (ETH.IsMemberEqualsValueExpression(be, GetType(Place), "State")) Then
                    _locations.Add(ETH.GetValueFromEqualsExpression(be, GetType(Place), "State"))
                    Return be
                Else
                    Return MyBase.VisitBinary(be)
                End If
            Else
                Return MyBase.VisitBinary(be)
            End If
        End Function
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    
    namespace LinqToTerraServerProvider
    {
        internal class LocationFinder : ExpressionVisitor
        {
            private Expression expression;
            private List<string> locations;
    
            public LocationFinder(Expression exp)
            {
                this.expression = exp;
            }
    
            public List<string> Locations
            {
                get
                {
                    if (locations == null)
                    {
                        locations = new List<string>();
                        this.Visit(this.expression);
                    }
                    return this.locations;
                }
            }
    
            protected override Expression VisitBinary(BinaryExpression be)
            {
                if (be.NodeType == ExpressionType.Equal)
                {
                    if (ExpressionTreeHelpers.IsMemberEqualsValueExpression(be, typeof(Place), "Name"))
                    {
                        locations.Add(ExpressionTreeHelpers.GetValueFromEqualsExpression(be, typeof(Place), "Name"));
                        return be;
                    }
                    else if (ExpressionTreeHelpers.IsMemberEqualsValueExpression(be, typeof(Place), "State"))
                    {
                        locations.Add(ExpressionTreeHelpers.GetValueFromEqualsExpression(be, typeof(Place), "State"));
                        return be;
                    }
                    else
                        return base.VisitBinary(be);
                }
                else
                    return base.VisitBinary(be);
            }
        }
    }
    

    Bu sınıf istemci geçirir ve karşılaştırma konum bilgileri ayıklamak için kullanılan Queryable.Where.Türetildiği ExpressionVisitor sınıf ve geçersiz kılmalar sadece VisitBinary yöntem.

    ExpressionVisitor Sınıfı, ikili ifadeler gönderir, eşitlik gibi ifadeler ister place.Name == "Seattle" (place.Name = "Seattle" , Visual Basic), to VisitBinary yöntem.Bu geçersiz kılma, VisitBinary bilgi ayıklanır ve konumların bir listesini saklanan konum bilgisini sağlayan eşitlik ifade deseninde ifade eşleşirse yöntemi.

    Bu sınıf bir ifade ağacı ziyaretçi ziyaretçi geçme ve ifade ağaçları incelemek için tasarlanmış olduğu için ifadesi ağacında konum bilgileri bulmak için kullanır.Sonuçta elde edilen neater ve daha az hataya ziyaretçi kullanmadan uygulandığı, dan kodudur.

    İzlenecek bu aşamada sağlayıcınız sorgu konum bilgileri sağlayarak, yalnızca sınırlı yolları da destekler.Konu konum bilgileri sağlayarak daha fazla yolları etkinleştirmek için işlevselliği siz ekleyeceksiniz.

İfade ağacını değiştirir ziyaretçi oluşturmak için

  • Ekleme ExpressionTreeModifier sınıf projenize.

    Imports System.Linq.Expressions
    
    Friend Class ExpressionTreeModifier
        Inherits ExpressionVisitor
    
        Private queryablePlaces As IQueryable(Of Place)
    
        Friend Sub New(ByVal places As IQueryable(Of Place))
            Me.queryablePlaces = places
        End Sub
    
        Protected Overrides Function VisitConstant(ByVal c As ConstantExpression) As Expression
            ' Replace the constant QueryableTerraServerData arg with the queryable Place collection.
            If c.Type Is GetType(QueryableTerraServerData(Of Place)) Then
                Return Expression.Constant(Me.queryablePlaces)
            Else
                Return c
            End If
        End Function
    End Class
    
    using System;
    using System.Linq;
    using System.Linq.Expressions;
    
    namespace LinqToTerraServerProvider
    {
        internal class ExpressionTreeModifier : ExpressionVisitor
        {
            private IQueryable<Place> queryablePlaces;
    
            internal ExpressionTreeModifier(IQueryable<Place> places)
            {
                this.queryablePlaces = places;
            }
    
            protected override Expression VisitConstant(ConstantExpression c)
            {
                // Replace the constant QueryableTerraServerData arg with the queryable Place collection.
                if (c.Type == typeof(QueryableTerraServerData<Place>))
                    return Expression.Constant(this.queryablePlaces);
                else
                    return c;
            }
        }
    }
    

    Bu sınıfın türetildiği ExpressionVisitor sınıfı hem de geçersiz kılmaları VisitConstant yöntem.Bu yöntemde, en içteki standart sorgu işleci çağrı uygulandığı nesne somut bir listesi ile değiştirir Place nesneler.

    Ziyaretçi gezer, incelemek ve ifade ağaçlarını kopyalamak için tasarlanmış olduğu için bu ifade ağaç değiştirici sınıfı ifade ağaç ziyaretçi kullanır.Bu sınıf temel ifade ağaç ziyaretçi sınıfından türeterek kendi işlevi gerçekleştirmek için çok az kod gerektirir.

İfade değerlendirici ekleme

İçin geçirilen karşılaştırma Queryable.Where istemci sorgu yöntemi lambda ifadesi parametresine bağlı olmayan sub-expressions içeriyor olabilir.Bu yalıtılmış sub-expressions olabilir ve hemen değerlendirilmesi gerekir.Bunlar yerel değişkenler veya değerlere çevrilmiş üye değişkenleri başvuruları olabilir.

Sonraki sınıf bir yöntem sunan PartialEval(Expression), belirleyen, varsa, alt ifadenin hemen değerlendirilebilir.Lambda ifadesi, derleme ve dönen temsilci çağırma sonra ifadeleri değerlendirir.Son olarak, alt ağacı sabit değeri temsil eden yeni bir düğüm değiştirir.Bu kısmi değerlendirme bilinir.

Bir ifade ağacı kısmi değerlendirmesi yapmak için bir sınıf eklemek için

  • Ekleme Evaluator sınıf projenize.

    Imports System.Linq.Expressions
    
    Public Module Evaluator
        ''' <summary>Performs evaluation and replacement of independent sub-trees</summary>
        ''' <param name="expr">The root of the expression tree.</param>
        ''' <param name="fnCanBeEvaluated">A function that decides whether a given expression node can be part of the local function.</param>
        ''' <returns>A new tree with sub-trees evaluated and replaced.</returns>
        Public Function PartialEval(
            ByVal expr As Expression, 
            ByVal fnCanBeEvaluated As Func(Of Expression, Boolean)
            )  As Expression
    
            Return New SubtreeEvaluator(New Nominator(fnCanBeEvaluated).Nominate(expr)).Eval(expr)
        End Function
    
        ''' <summary>
        ''' Performs evaluation and replacement of independent sub-trees
        ''' </summary>
        ''' <param name="expression">The root of the expression tree.</param>
        ''' <returns>A new tree with sub-trees evaluated and replaced.</returns>
        Public Function PartialEval(ByVal expression As Expression) As Expression
            Return PartialEval(expression, AddressOf Evaluator.CanBeEvaluatedLocally)
        End Function
    
        Private Function CanBeEvaluatedLocally(ByVal expression As Expression) As Boolean
            Return expression.NodeType <> ExpressionType.Parameter
        End Function
    
        ''' <summary>
        ''' Evaluates and replaces sub-trees when first candidate is reached (top-down)
        ''' </summary>
        Class SubtreeEvaluator
            Inherits ExpressionVisitor
    
            Private candidates As HashSet(Of Expression)
    
            Friend Sub New(ByVal candidates As HashSet(Of Expression))
                Me.candidates = candidates
            End Sub
    
            Friend Function Eval(ByVal exp As Expression) As Expression
                Return Me.Visit(exp)
            End Function
    
            Public Overrides Function Visit(ByVal exp As Expression) As Expression
                If exp Is Nothing Then
                    Return Nothing
                ElseIf Me.candidates.Contains(exp) Then
                    Return Me.Evaluate(exp)
                End If
    
                Return MyBase.Visit(exp)
            End Function
    
            Private Function Evaluate(ByVal e As Expression) As Expression
                If e.NodeType = ExpressionType.Constant Then
                    Return e
                End If
    
                Dim lambda = Expression.Lambda(e)
                Dim fn As [Delegate] = lambda.Compile()
    
                Return Expression.Constant(fn.DynamicInvoke(Nothing), e.Type)
            End Function
        End Class
    
    
        ''' <summary>
        ''' Performs bottom-up analysis to determine which nodes can possibly
        ''' be part of an evaluated sub-tree.
        ''' </summary>
        Class Nominator
            Inherits ExpressionVisitor
    
            Private fnCanBeEvaluated As Func(Of Expression, Boolean)
            Private candidates As HashSet(Of Expression)
            Private cannotBeEvaluated As Boolean
    
            Friend Sub New(ByVal fnCanBeEvaluated As Func(Of Expression, Boolean))
                Me.fnCanBeEvaluated = fnCanBeEvaluated
            End Sub
    
            Friend Function Nominate(ByVal expr As Expression) As HashSet(Of Expression)
                Me.candidates = New HashSet(Of Expression)()
                Me.Visit(expr)
    
                Return Me.candidates
            End Function
    
            Public Overrides Function Visit(ByVal expr As Expression) As Expression
                If expr IsNot Nothing Then
    
                    Dim saveCannotBeEvaluated = Me.cannotBeEvaluated
                    Me.cannotBeEvaluated = False
    
                    MyBase.Visit(expr)
    
                    If Not Me.cannotBeEvaluated Then
                        If Me.fnCanBeEvaluated(expr) Then
                            Me.candidates.Add(expr)
                        Else
                            Me.cannotBeEvaluated = True
                        End If
                    End If
    
                    Me.cannotBeEvaluated = Me.cannotBeEvaluated Or 
                                           saveCannotBeEvaluated
                End If
    
                Return expr
            End Function
        End Class
    End Module
    
    using System;
    using System.Collections.Generic;
    using System.Linq.Expressions;
    
    namespace LinqToTerraServerProvider
    {
        public static class Evaluator
        {
            /// <summary>
            /// Performs evaluation & replacement of independent sub-trees
            /// </summary>
            /// <param name="expression">The root of the expression tree.</param>
            /// <param name="fnCanBeEvaluated">A function that decides whether a given expression node can be part of the local function.</param>
            /// <returns>A new tree with sub-trees evaluated and replaced.</returns>
            public static Expression PartialEval(Expression expression, Func<Expression, bool> fnCanBeEvaluated)
            {
                return new SubtreeEvaluator(new Nominator(fnCanBeEvaluated).Nominate(expression)).Eval(expression);
            }
    
            /// <summary>
            /// Performs evaluation & replacement of independent sub-trees
            /// </summary>
            /// <param name="expression">The root of the expression tree.</param>
            /// <returns>A new tree with sub-trees evaluated and replaced.</returns>
            public static Expression PartialEval(Expression expression)
            {
                return PartialEval(expression, Evaluator.CanBeEvaluatedLocally);
            }
    
            private static bool CanBeEvaluatedLocally(Expression expression)
            {
                return expression.NodeType != ExpressionType.Parameter;
            }
    
            /// <summary>
            /// Evaluates & replaces sub-trees when first candidate is reached (top-down)
            /// </summary>
            class SubtreeEvaluator : ExpressionVisitor
            {
                HashSet<Expression> candidates;
    
                internal SubtreeEvaluator(HashSet<Expression> candidates)
                {
                    this.candidates = candidates;
                }
    
                internal Expression Eval(Expression exp)
                {
                    return this.Visit(exp);
                }
    
                public override Expression Visit(Expression exp)
                {
                    if (exp == null)
                    {
                        return null;
                    }
                    if (this.candidates.Contains(exp))
                    {
                        return this.Evaluate(exp);
                    }
                    return base.Visit(exp);
                }
    
                private Expression Evaluate(Expression e)
                {
                    if (e.NodeType == ExpressionType.Constant)
                    {
                        return e;
                    }
                    LambdaExpression lambda = Expression.Lambda(e);
                    Delegate fn = lambda.Compile();
                    return Expression.Constant(fn.DynamicInvoke(null), e.Type);
                }
            }
    
            /// <summary>
            /// Performs bottom-up analysis to determine which nodes can possibly
            /// be part of an evaluated sub-tree.
            /// </summary>
            class Nominator : ExpressionVisitor
            {
                Func<Expression, bool> fnCanBeEvaluated;
                HashSet<Expression> candidates;
                bool cannotBeEvaluated;
    
                internal Nominator(Func<Expression, bool> fnCanBeEvaluated)
                {
                    this.fnCanBeEvaluated = fnCanBeEvaluated;
                }
    
                internal HashSet<Expression> Nominate(Expression expression)
                {
                    this.candidates = new HashSet<Expression>();
                    this.Visit(expression);
                    return this.candidates;
                }
    
                public override Expression Visit(Expression expression)
                {
                    if (expression != null)
                    {
                        bool saveCannotBeEvaluated = this.cannotBeEvaluated;
                        this.cannotBeEvaluated = false;
                        base.Visit(expression);
                        if (!this.cannotBeEvaluated)
                        {
                            if (this.fnCanBeEvaluated(expression))
                            {
                                this.candidates.Add(expression);
                            }
                            else
                            {
                                this.cannotBeEvaluated = true;
                            }
                        }
                        this.cannotBeEvaluated |= saveCannotBeEvaluated;
                    }
                    return expression;
                }
            }
        }
    }
    

Yardımcı sınıfları ekleme

Bu bölümde, sağlayıcınız için üç yardımcı sınıf kodunu içerir.

System.Linq.IQueryProvider uygulaması tarafından kullanılan yardımcı sınıf eklemek için

  • Ekleme TypeSystem sınıf (veya modülü Visual Basic) projenize.

    Imports System.Collections.Generic
    
    Friend Module TypeSystem
    
        Friend Function GetElementType(ByVal seqType As Type) As Type
            Dim ienum As Type = FindIEnumerable(seqType)
    
            If ienum Is Nothing Then
                Return seqType
            End If
    
            Return ienum.GetGenericArguments()(0)
        End Function
    
        Private Function FindIEnumerable(ByVal seqType As Type) As Type
    
            If seqType Is Nothing Or seqType Is GetType(String) Then
                Return Nothing
            End If
    
            If (seqType.IsArray) Then
                Return GetType(IEnumerable(Of )).MakeGenericType(seqType.GetElementType())
            End If
    
            If (seqType.IsGenericType) Then
                For Each arg As Type In seqType.GetGenericArguments()
                    Dim ienum As Type = GetType(IEnumerable(Of )).MakeGenericType(arg)
    
                    If (ienum.IsAssignableFrom(seqType)) Then
                        Return ienum
                    End If
                Next
            End If
    
            Dim ifaces As Type() = seqType.GetInterfaces()
    
            If ifaces IsNot Nothing And ifaces.Length > 0 Then
                For Each iface As Type In ifaces
                    Dim ienum As Type = FindIEnumerable(iface)
    
                    If (ienum IsNot Nothing) Then
                        Return ienum
                    End If
                Next
            End If
    
            If seqType.BaseType IsNot Nothing AndAlso
               seqType.BaseType IsNot GetType(Object) Then
    
                Return FindIEnumerable(seqType.BaseType)
            End If
    
            Return Nothing
        End Function
    End Module
    
    using System;
    using System.Collections.Generic;
    
    namespace LinqToTerraServerProvider
    {
        internal static class TypeSystem
        {
            internal static Type GetElementType(Type seqType)
            {
                Type ienum = FindIEnumerable(seqType);
                if (ienum == null) return seqType;
                return ienum.GetGenericArguments()[0];
            }
    
            private static Type FindIEnumerable(Type seqType)
            {
                if (seqType == null || seqType == typeof(string))
                    return null;
    
                if (seqType.IsArray)
                    return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType());
    
                if (seqType.IsGenericType)
                {
                    foreach (Type arg in seqType.GetGenericArguments())
                    {
                        Type ienum = typeof(IEnumerable<>).MakeGenericType(arg);
                        if (ienum.IsAssignableFrom(seqType))
                        {
                            return ienum;
                        }
                    }
                }
    
                Type[] ifaces = seqType.GetInterfaces();
                if (ifaces != null && ifaces.Length > 0)
                {
                    foreach (Type iface in ifaces)
                    {
                        Type ienum = FindIEnumerable(iface);
                        if (ienum != null) return ienum;
                    }
                }
    
                if (seqType.BaseType != null && seqType.BaseType != typeof(object))
                {
                    return FindIEnumerable(seqType.BaseType);
                }
    
                return null;
            }
        }
    }
    

    IQueryProvider Daha önce eklenen uygulama bu yardımcı sınıf kullanır.

    TypeSystem.GetElementTypeYansıma genel tür bağımsız değişkeni elde etmek için kullandığı bir IEnumerable<T> (IEnumerable(Of T) , Visual Basic) koleksiyonu.Genel olmayan bu yöntem çaðrýlýr CreateQuery öğe türü sorgu sonucu koleksiyonunun sağlamak için sorgu sağlayıcısı uygulama yöntemi.

    Bu yardımcı sınıf bu usa TerraServer Web servis sağlayıcıya özgü değildir.Bu nedenle, bunun için yeniden kullanılabilir LINQ sağlayıcı.

Bir ifade ağacı yardımcı sınıfı oluşturmak için

  • Ekleme ExpressionTreeHelpers sınıf projenize.

    Imports System.Linq.Expressions
    
    Friend Class ExpressionTreeHelpers
        ' Visual Basic encodes string comparisons as a method call to
        ' Microsoft.VisualBasic.CompilerServices.Operators.CompareString.
        ' This method will convert the method call into a binary operation instead.
        ' Note that this makes the string comparison case sensitive.
        Friend Shared Function ConvertVBStringCompare(ByVal exp As BinaryExpression) As BinaryExpression
    
            If exp.Left.NodeType = ExpressionType.Call Then
                Dim compareStringCall = CType(exp.Left, MethodCallExpression)
    
                If compareStringCall.Method.DeclaringType.FullName = 
                    "Microsoft.VisualBasic.CompilerServices.Operators" AndAlso 
                    compareStringCall.Method.Name = "CompareString" Then
    
                    Dim arg1 = compareStringCall.Arguments(0)
                    Dim arg2 = compareStringCall.Arguments(1)
    
                    Select Case exp.NodeType
                        Case ExpressionType.LessThan
                            Return Expression.LessThan(arg1, arg2)
                        Case ExpressionType.LessThanOrEqual
                            Return Expression.GreaterThan(arg1, arg2)
                        Case ExpressionType.GreaterThan
                            Return Expression.GreaterThan(arg1, arg2)
                        Case ExpressionType.GreaterThanOrEqual
                            Return Expression.GreaterThanOrEqual(arg1, arg2)
                        Case Else
                            Return Expression.Equal(arg1, arg2)
                    End Select
                End If
            End If
            Return exp
        End Function
    
        Friend Shared Function IsMemberEqualsValueExpression(
            ByVal exp As Expression, 
            ByVal declaringType As Type, 
            ByVal memberName As String) As Boolean
    
            If exp.NodeType <> ExpressionType.Equal Then
                Return False
            End If
    
            Dim be = CType(exp, BinaryExpression)
    
            ' Assert.
            If IsSpecificMemberExpression(be.Left, declaringType, memberName) AndAlso 
               IsSpecificMemberExpression(be.Right, declaringType, memberName) Then
    
                Throw New Exception("Cannot have 'member' = 'member' in an expression!")
            End If
    
            Return IsSpecificMemberExpression(be.Left, declaringType, memberName) OrElse 
                   IsSpecificMemberExpression(be.Right, declaringType, memberName)
        End Function
    
    
        Friend Shared Function IsSpecificMemberExpression(
            ByVal exp As Expression, 
            ByVal declaringType As Type, 
            ByVal memberName As String) As Boolean
    
            Return (TypeOf exp Is MemberExpression) AndAlso 
                   (CType(exp, MemberExpression).Member.DeclaringType Is declaringType) AndAlso 
                   (CType(exp, MemberExpression).Member.Name = memberName)
        End Function
    
    
        Friend Shared Function GetValueFromEqualsExpression(
            ByVal be As BinaryExpression, 
            ByVal memberDeclaringType As Type, 
            ByVal memberName As String) As String
    
            If be.NodeType <> ExpressionType.Equal Then
                Throw New Exception("There is a bug in this program.")
            End If
    
            If be.Left.NodeType = ExpressionType.MemberAccess Then
                Dim mEx = CType(be.Left, MemberExpression)
    
                If mEx.Member.DeclaringType Is memberDeclaringType AndAlso 
                   mEx.Member.Name = memberName Then
                    Return GetValueFromExpression(be.Right)
                End If
            ElseIf be.Right.NodeType = ExpressionType.MemberAccess Then
                Dim mEx = CType(be.Right, MemberExpression)
    
                If mEx.Member.DeclaringType Is memberDeclaringType AndAlso 
                   mEx.Member.Name = memberName Then
                    Return GetValueFromExpression(be.Left)
                End If
            End If
    
            ' We should have returned by now.
            Throw New Exception("There is a bug in this program.")
        End Function
    
        Friend Shared Function GetValueFromExpression(ByVal expr As expression) As String
            If expr.NodeType = ExpressionType.Constant Then
                Return CStr(CType(expr, ConstantExpression).Value)
            Else
                Dim s = "The expression type {0} is not supported to obtain a value."
                Throw New InvalidQueryException(String.Format(s, expr.NodeType))
            End If
        End Function
    End Class
    
    using System;
    using System.Linq.Expressions;
    
    namespace LinqToTerraServerProvider
    {
        internal class ExpressionTreeHelpers
        {
            internal static bool IsMemberEqualsValueExpression(Expression exp, Type declaringType, string memberName)
            {
                if (exp.NodeType != ExpressionType.Equal)
                    return false;
    
                BinaryExpression be = (BinaryExpression)exp;
    
                // Assert.
                if (ExpressionTreeHelpers.IsSpecificMemberExpression(be.Left, declaringType, memberName) &&
                    ExpressionTreeHelpers.IsSpecificMemberExpression(be.Right, declaringType, memberName))
                    throw new Exception("Cannot have 'member' == 'member' in an expression!");
    
                return (ExpressionTreeHelpers.IsSpecificMemberExpression(be.Left, declaringType, memberName) ||
                    ExpressionTreeHelpers.IsSpecificMemberExpression(be.Right, declaringType, memberName));
            }
    
            internal static bool IsSpecificMemberExpression(Expression exp, Type declaringType, string memberName)
            {
                return ((exp is MemberExpression) &&
                    (((MemberExpression)exp).Member.DeclaringType == declaringType) &&
                    (((MemberExpression)exp).Member.Name == memberName));
            }
    
            internal static string GetValueFromEqualsExpression(BinaryExpression be, Type memberDeclaringType, string memberName)
            {
                if (be.NodeType != ExpressionType.Equal)
                    throw new Exception("There is a bug in this program.");
    
                if (be.Left.NodeType == ExpressionType.MemberAccess)
                {
                    MemberExpression me = (MemberExpression)be.Left;
    
                    if (me.Member.DeclaringType == memberDeclaringType && me.Member.Name == memberName)
                    {
                        return GetValueFromExpression(be.Right);
                    }
                }
                else if (be.Right.NodeType == ExpressionType.MemberAccess)
                {
                    MemberExpression me = (MemberExpression)be.Right;
    
                    if (me.Member.DeclaringType == memberDeclaringType && me.Member.Name == memberName)
                    {
                        return GetValueFromExpression(be.Left);
                    }
                }
    
                // We should have returned by now.
                throw new Exception("There is a bug in this program.");
            }
    
            internal static string GetValueFromExpression(Expression expression)
            {
                if (expression.NodeType == ExpressionType.Constant)
                    return (string)(((ConstantExpression)expression).Value);
                else
                    throw new InvalidQueryException(
                        String.Format("The expression type {0} is not supported to obtain a value.", expression.NodeType));
            }
        }
    }
    

    Bu sınıf hakkında bilgileri belirlemek ve belirli tür ifade ağaçları arasında veri ayıklamak için kullanılan yöntemleri içerir.Bu sağlayıcı bu yöntemler tarafından kullanılan LocationFinder sorguyu temsil eden ifade ağaçtan konum bilgileri ayıklamak için sınıf.

Geçersiz sorgu için bir özel durum türü eklemek için

  • Ekleme InvalidQueryException sınıf projenize.

    Public Class InvalidQueryException
        Inherits Exception
    
        Private _message As String
    
        Public Sub New(ByVal message As String)
            Me._message = message & " "
        End Sub
    
        Public Overrides ReadOnly Property Message() As String
            Get
                Return "The client query is invalid: " & _message
            End Get
        End Property
    End Class
    
    using System;
    
    namespace LinqToTerraServerProvider
    {
        class InvalidQueryException : System.Exception
        {
            private string message;
    
            public InvalidQueryException(string message)
            {
                this.message = message + " ";
            }
    
            public override string Message
            {
                get
                {
                    return "The client query is invalid: " + message;
                }
            }
        }
    }
    

    Bu sınıf tanımlar bir Exception anlamak, sağlayıcınız atabilirsiniz türü LINQ istemci sorgu.Geçersiz sorgu bu özel durum türü tanımlayarak, sağlayıcı daha daha belirli bir özel durum sadece Exception kod içinde çeşitli yerlerde.

Şimdi, sağlayıcınız derlemek için gerekli tüm parçaları eklediniz.Yapı LinqToTerraServerProvider proje ve hiçbir derleme hataları olduğunu doğrulayın.

LINQ sağlayıcı test etmek

Test edebilirsiniz, LINQ bir istemci uygulaması oluşturarak sağlayıcı içerir bir LINQ , veri kaynağına yönelik sorgu.

Sağlayıcınızı test etmek için bir istemci uygulaması oluşturmak için

  1. Yeni bir ekleme Konsol uygulaması olarak adlandırın ve proje, çözümünüz için ClientApp.

  2. Yeni projede sağlayıcı bütünleştirilmiş koduna başvuru ekleyin.

  3. Sürükleme app.config sağlayıcı projenize bir dosyadan istemci projesine.(Bu dosya Web hizmetiyle iletişim kurmak için gereklidir.)

    [!NOT]

    İçinde Visual Basic, tıklatmanız gerekebilir Tüm dosyaları göster görmek için düğmeyi app.config içinde dosya Çözüm Gezgini.

  4. Aşağıdaki using ifadeleri (Imports deyiminde Visual Basic) için Program.cs (veya Module1.vb , Visual Basic) dosyası:

    using System;
    using System.Linq;
    using LinqToTerraServerProvider;
    
    Imports LinqToTerraServerProvider
    
  5. İçinde Main dosyasındaki yöntemi Program.cs (veya Module1.vb , Visual Basic), aşağıdaki kodu ekleyin:

    QueryableTerraServerData<Place> terraPlaces = new QueryableTerraServerData<Place>();
    
    var query = from place in terraPlaces
                where place.Name == "Johannesburg"
                select place.PlaceType;
    
    foreach (PlaceType placeType in query)
        Console.WriteLine(placeType);
    
    Dim terraPlaces As New QueryableTerraServerData(Of Place)
    
    Dim query = From place In terraPlaces 
                Where place.Name = "Johannesburg" 
                Select place.PlaceType
    
    For Each placeType In query
        Console.WriteLine(placeType.ToString())
    Next
    

    Bu kod, yeni bir örneğini oluşturur IQueryable<T> olarak tanımlanan tür ve nesne kullanarak sorguları LINQ.Sorgu eşitlik deyimi kullanarak, verileri almak için bir konum belirtir.Implements veri kaynağı olduğundan IQueryable, sorgu ifade sözdizimi derleyici tanımlanmış standart sorgu işleçler çağrı dönüştürecektir Queryable.Dahili olarak bu standart sorgu işleci yöntemleri bir ifade ağacı ve çağrı yapı Execute veya CreateQuery bir parçası olarak uygulanan yöntemler, IQueryProvider uygulaması.

  6. Yapı ClientApp.

  7. Bu istemci uygulaması, çözümünüz için "Başlangıç" projesi olarak ayarlayın.İçinde Çözüm Gezgini, sağ ClientApp seçin ve proje başlangıç projesi olarak ayarla.

  8. Programı çalıştırın ve sonuçları görüntüleyin.Yaklaşık üç sonuç olmalıdır.

Daha karmaşık sorgu özellikleri ekleme

Bu noktada olan sağlayıcı istemcilerin konum bilgilerini belirtmek çok sınırlı bir yol sağlar LINQ sorgu.Özellikle, sağlayıcı yalnızca konum bilgileri gibi gelen eşitlik ifadeleri alma olanağınız Place.Name == "Seattle" veya Place.State == "Alaska" (Place.Name = "Seattle" veya Place.State = "Alaska" , Visual Basic).

Sonraki yordamda konum bilgileri belirten bir ek yol desteği eklemek gösterilmiştir.Bu kodu ekledikten sonra sağlayıcınız konum bilgisi gelen yöntemi çağrısı ifadeleri gibi ayıklayabilirsiniz place.Name.StartsWith("Seat").

String.StartsWith içeren yüklemler desteği eklemek için

  1. İçinde LinqToTerraServerProvider projesi, eklemek VisitMethodCall yöntemine LocationFinder sınıf tanımı.

    Protected Overrides Function VisitMethodCall(ByVal m As MethodCallExpression) As Expression
        If m.Method.DeclaringType Is GetType(String) And m.Method.Name = "StartsWith" Then
            If ETH.IsSpecificMemberExpression(m.Object, GetType(Place), "Name") OrElse
               ETH.IsSpecificMemberExpression(m.Object, GetType(Place), "State") Then
                _locations.Add(ETH.GetValueFromExpression(m.Arguments(0)))
                Return m
            End If
        End If
    
        Return MyBase.VisitMethodCall(m)
    End Function
    
    protected override Expression VisitMethodCall(MethodCallExpression m)
    {
        if (m.Method.DeclaringType == typeof(String) && m.Method.Name == "StartsWith")
        {
            if (ExpressionTreeHelpers.IsSpecificMemberExpression(m.Object, typeof(Place), "Name") ||
            ExpressionTreeHelpers.IsSpecificMemberExpression(m.Object, typeof(Place), "State"))
            {
                locations.Add(ExpressionTreeHelpers.GetValueFromExpression(m.Arguments[0]));
                return m;
            }
        }
    
        return base.VisitMethodCall(m);
    }
    
  2. Derlemeniz LinqToTerraServerProvider proje.

  3. Sağlayıcınızın yeni özelliği test etmek için dosyayı açmak Program.cs (veya Module1.vb , Visual Basic), ClientApp proje.Kodu Değiştir Main yöntemini aşağıdaki kod ile:

    QueryableTerraServerData<Place> terraPlaces = new QueryableTerraServerData<Place>();
    
    var query = from place in terraPlaces
                where place.Name.StartsWith("Lond")
                select new { place.Name, place.State };
    
    foreach (var obj in query)
        Console.WriteLine(obj);
    
    Dim terraPlaces As New QueryableTerraServerData(Of Place)
    
    Dim query = From place In terraPlaces 
                Where place.Name.StartsWith("Lond") 
                Select place.Name, place.State
    
    For Each obj In query
        Console.WriteLine(obj)
    Next
    
  4. Programı çalıştırın ve sonuçları görüntüleyin.Yaklaşık 29 sonuçlar olmalıdır.

Sonraki yordamda, özellikle iki ek yöntemleri kullanarak konum bilgilerini belirtmek istemci sorgu etkinleştirmek için sağlayıcınıza işlevselliği eklemek nasıl gösterir Enumerable.Contains ve List<T>.Contains.Bu kodu ekledikten sonra sağlayıcınız konum bilgileri istemci sorgu yöntemi çağrısı ifadelerde gibi ayıklamak mümkün placeList.Contains(place.Name), placeList koleksiyonu ise istemcinin sağladığı somut bir liste.Kullanan istemcilerin izin vererek avantajı Contains yöntemidir bunlar yalnızca ekleyerek konumlardan herhangi bir sayıda belirtebilirsiniz placeList.Sorgu sözdizimi konumları sayısı değişen değiştirmez.

CONTAINS yöntemi kendi 'where' yan tümcesinde sorguları desteği eklemek için

  1. İçinde LinqToTerraServerProvider de, proje LocationFinder sınıf tanımının, yerine VisitMethodCall yöntemini aşağıdaki kod ile:

    Protected Overrides Function VisitMethodCall(ByVal m As MethodCallExpression) As Expression
        If m.Method.DeclaringType Is GetType(String) And m.Method.Name = "StartsWith" Then
            If ETH.IsSpecificMemberExpression(m.Object, GetType(Place), "Name") OrElse
               ETH.IsSpecificMemberExpression(m.Object, GetType(Place), "State") Then
                _locations.Add(ETH.GetValueFromExpression(m.Arguments(0)))
                Return m
            End If
        ElseIf m.Method.Name = "Contains" Then
            Dim valuesExpression As Expression = Nothing
    
            If m.Method.DeclaringType Is GetType(Enumerable) Then
                If ETH.IsSpecificMemberExpression(m.Arguments(1), GetType(Place), "Name") OrElse
                   ETH.IsSpecificMemberExpression(m.Arguments(1), GetType(Place), "State") Then
                    valuesExpression = m.Arguments(0)
                End If
    
            ElseIf m.Method.DeclaringType Is GetType(List(Of String)) Then
                If ETH.IsSpecificMemberExpression(m.Arguments(0), GetType(Place), "Name") OrElse
                   ETH.IsSpecificMemberExpression(m.Arguments(0), GetType(Place), "State") Then
                    valuesExpression = m.Object
                End If
            End If
    
            If valuesExpression Is Nothing OrElse valuesExpression.NodeType <> ExpressionType.Constant Then
                Throw New Exception("Could not find the location values.")
            End If
    
            Dim ce = CType(valuesExpression, ConstantExpression)
    
            Dim placeStrings = CType(ce.Value, IEnumerable(Of String))
            ' Add each string in the collection to the list of locations to obtain data about.
            For Each place In placeStrings
                _locations.Add(place)
            Next
    
            Return m
        End If
    
        Return MyBase.VisitMethodCall(m)
    End Function
    
    protected override Expression VisitMethodCall(MethodCallExpression m)
    {
        if (m.Method.DeclaringType == typeof(String) && m.Method.Name == "StartsWith")
        {
            if (ExpressionTreeHelpers.IsSpecificMemberExpression(m.Object, typeof(Place), "Name") ||
            ExpressionTreeHelpers.IsSpecificMemberExpression(m.Object, typeof(Place), "State"))
            {
                locations.Add(ExpressionTreeHelpers.GetValueFromExpression(m.Arguments[0]));
                return m;
            }
    
        }
        else if (m.Method.Name == "Contains")
        {
            Expression valuesExpression = null;
    
            if (m.Method.DeclaringType == typeof(Enumerable))
            {
                if (ExpressionTreeHelpers.IsSpecificMemberExpression(m.Arguments[1], typeof(Place), "Name") ||
                ExpressionTreeHelpers.IsSpecificMemberExpression(m.Arguments[1], typeof(Place), "State"))
                {
                    valuesExpression = m.Arguments[0];
                }
            }
            else if (m.Method.DeclaringType == typeof(List<string>))
            {
                if (ExpressionTreeHelpers.IsSpecificMemberExpression(m.Arguments[0], typeof(Place), "Name") ||
                ExpressionTreeHelpers.IsSpecificMemberExpression(m.Arguments[0], typeof(Place), "State"))
                {
                    valuesExpression = m.Object;
                }
            }
    
            if (valuesExpression == null || valuesExpression.NodeType != ExpressionType.Constant)
                throw new Exception("Could not find the location values.");
    
            ConstantExpression ce = (ConstantExpression)valuesExpression;
    
            IEnumerable<string> placeStrings = (IEnumerable<string>)ce.Value;
            // Add each string in the collection to the list of locations to obtain data about.
            foreach (string place in placeStrings)
                locations.Add(place);
    
            return m;
        }
    
        return base.VisitMethodCall(m);
    }
    

    Bu yöntem, koleksiyondaki her dize ekler, Contains ile Web sorgu konumlar listesine hizmet için uygulanır.Adlı bir yöntem Contains ikisini de tanımlı Enumerable ve List<T>.Bu nedenle, VisitMethodCall yöntemi bu iki türleri bildirmek için kontrol gerekir.Enumerable.Containsbir genişletme yöntemi tanımlanır; Bu nedenle koleksiyon için uygulanan yöntemi aslında ilk bağımsız değişkenidir.List.Containsbir örnek yöntemi tanımlanır; Bu nedenle için uygulanan yöntemin alıcı nesne koleksiyonudur.

  2. Derlemeniz LinqToTerraServerProvider proje.

  3. Sağlayıcınızın yeni özelliği test etmek için dosyayı açmak Program.cs (veya Module1.vb , Visual Basic), ClientApp proje.Kodu Değiştir Main yöntemini aşağıdaki kod ile:

    QueryableTerraServerData<Place> terraPlaces = new QueryableTerraServerData<Place>();
    
    string[] places = { "Johannesburg", "Yachats", "Seattle" };
    
    var query = from place in terraPlaces
                where places.Contains(place.Name)
                orderby place.State
                select new { place.Name, place.State };
    
    foreach (var obj in query)
        Console.WriteLine(obj);
    
    Dim terraPlaces As New QueryableTerraServerData(Of Place)
    
    Dim places = New String() {"Johannesburg", "Yachats", "Seattle"}
    
    Dim query = From place In terraPlaces 
                Where places.Contains(place.Name) 
                Order By place.State 
                Select place.Name, place.State
    
    For Each obj In query
        Console.WriteLine(obj)
    Next
    
  4. Programı çalıştırın ve sonuçları görüntüleyin.Yaklaşık 5 sonuçları olmalıdır.

Sonraki Adımlar

Bu izlenecek yol konusunda nasıl oluşturulacağını gösterir bir LINQ sağlayıcı için bir Web hizmeti yöntemi.Ek geliştirilmesini düşmek isterseniz, bir LINQ sağlayıcı, bu olasılıkları göz önünde bulundurun:

  • Etkinleştirme LINQ istemci sorgu içinde bir konum belirterek, diğer yolları işlemek için sağlayıcı.

  • Türkiye TerraServer Web hizmet sunar ve oluşturmak diğer yöntemleri araştırmak bir LINQ bu yöntemlerden birini arabirimleri sağlayıcısı.

  • İlgilendiğiniz ve oluşturmak farklı bir Web hizmeti bulma bir LINQ onun için sağlayıcı.

  • Oluşturma bir LINQ için bir veri kaynağı başka bir Web hizmeti sağlayıcısı.

Kendi LINQ sağlayıcı oluşturma hakkında daha fazla bilgi için bkz: LINQ: IQueryable sağlayıcı oluşturma , msdn Web günlükleri.

Ayrıca bkz.

Görevler

LINQ Örnekleri

Nasıl yapılır: deyim ağaçları (C# ve Visual Basic) değiştirme

Başvuru

IQueryable<T>

IOrderedQueryable<T>

Kavramlar

LINQ sorgulamak için bir veri kaynağı'nı etkinleştirme

Windows Communication Foundation hizmetlerini ve Visual Studio wcf Veri Hizmetleri