LINQ... - Autodesk

abashedwhimsicalSoftware and s/w Development

Nov 2, 2013 (3 years and 9 months ago)

174 views

©
2012
Autodesk

Using .NET to Query an AutoCAD® Drawing Database

James E. Johnson

Application Developer for
Synergis

Software

©
2012
Autodesk

CP1923

Using .NET to Query an AutoCAD® Drawing Database

This class is for AutoCAD® software developers who want to learn how to use generic
collections, LINQ (Language Integrated Query), delegates, anonymous methods,
extension methods, and other .NET features in their AutoCAD® applications. The class
will explore how to improve code for working with an AutoCAD® drawing database
when searching for data and getting collections, such as layers, layouts, and entities.
We will discuss using .NET dynamic types (DLR) with the AutoCAD® 2013 API. In this
class, you will learn the basics of using some intermediate to advanced .NET features
with the AutoCAD® API. LINQ is a .NET Framework component that allows querying
data much like SQL is used to query databases. DLR (Dynamic Language Runtime)
runs on top of the CLR (Common Language Runtime) and provides language services
for different languages.

©
2012
Autodesk

Learning Objectives

At the end of this class, you will be able to:


Query AutoCAD® drawing databases using LINQ


Create and use anonymous methods, delegates, and extension methods


Use generic and enumerable collections


Use .NET Dynamic Language Runtime with AutoCAD API

©
2012
Autodesk

Questions...


Using LINQ ?


Using Generic List<T> ?


Use Anonymous methods ?


Use Anonymous type

var


?


Using delegates ?


Using Object Initializers ?


Using Dynamic Type ?

©
2012
Autodesk

What is LINQ ("Language Integrated Query")
?


LINQ is a .NET programming model that adds querying capabilities to
.NET programming languages
.




Language Integrated Query


designates that these query
capabilities are accessible within the programming language(e.g., C#,
Visual Basic)
.



LINQ is available with .NET framework version 3.0 and newer
.



LINQ defines a standard set of query operators that can be used to
query objects and filter
datasources
.


©
2012
Autodesk

LINQ...

LINQ

Namespace in System.Core

.NET Languages

C#

VB.NET

OTHER…

NET LINQ (Language Integrated Query)

STANDARD

QUERY

OPERATORS

LINQ
ToSQL

PROVIDER


Objects

Relational
Databases

XML

LINQ To

XML

PROVIDER

Querying

Drawing

Database

objects

©
2012
Autodesk

LINQ basics...

var

layernames

=


from

oid

in
lt.Cast
<
ObjectId
>()


select

((
LayerTableRecord
)
tr,GetObject
(
oid
,
OpenMode.ForRead
,
false
)).Name;

var

layernames

=


lt.Cast
<
ObjectId
>()


.Select<
ObjectId
,
string
> (
oid

=>


{


return ((
LayerTableRecord
)tr.GetObject(
oid
,
OpenMode.ForRead
,
false
)).Name;


}

var

dbObjCollection

=
from

oid

in

btr.Cast<
ObjectId
>()


select new


{





DBObj
= (
DBObject
)
tr.GetObject
(
oid
,
OpenMode.ForRead
,
false
)




}
;

Query Expressions

Local Variable Type
Inference

Extension Methods

Lambda Expressions

Statement Expressions

Anonymous types

Object Initializers

©
2012
Autodesk


Dim

layernames

As List(Of
String
) =
lt.Cast
(Of
ObjectId
).Select(Of
LayerTableRecord
) _


(Function(
oid
)
DirectCast
(
tr.GetObject
(
oid
,
OpenMode.ForRead
, _


False),
LayerTableRecord
)) _


.Where(Function(
ltr
) (
ltr.IsFrozen
)).Select(Function(
ltr
) (
ltr.Name
)).
ToList
()




Dim

layernames

As List(Of
String
) =


(
From

oid

In
lt.Cast
(Of
ObjectId
)() _


Select

DirectCast
(
tr.GetObject
(
oid
,
OpenMode.ForRead
, False), _


LayerTableRecord
).Name)


.
ToList
()





Dim

dbObjCollection

=


From

oid

In
btr.Cast
(Of
ObjectId
)() _


Select

New
With

{.
DBObj

= _


DirectCast
(
tr.GetObject
(
oid
,
OpenMode.ForRead
, False),
DBObject
)}

LINQ
basics VB.
..

Local Variable Type
Inference

Extension Methods

Lambda Expressions

Object Initializers

Query Expressions

Anonymous types

©
2012
Autodesk

LINQ basics...


Query expressions





from
...
where
...
select



Extension
methods





.
select .
orderBy

.where .
Any



Local variable type
inference


var

dbTxt

= ...........
.











Dim

dbTxt

= ............


Lambda
Expressions




Func
<Point3d,
bool
>
pFiltX

=
p => (
p.X

> 4.0)
;











Function
(p) (
p.X

> 4.0
)



Anonymous
types





new

{

............
}











New
With

{

............
}



Object
Initializers





new

pointObj

{

X = 1, Y = 2
}






New

pointObj

With

{

.X = 1, .Y = 2
}







©
2012
Autodesk

Reasons to use LINQ...


Strongly typed arguments and results
.


Standard query syntax.


Fully extensible.


Intellisence


Easy to read and maintain.




©
2012
Autodesk

Visual Studio project requirements


To get started with LINQ, your
project needs to have its target
framework set to .NET
Framework 3.0 or newer.


Add using statements in the class…


using
System.Collections
;


using
System.Collections.Generic
;


using
System.Linq
;


using
System.Linq.Expressions
;

©
2012
Autodesk

Querying the AutoCAD® Database



Customizing for AutoCAD
®

applications often requires adding,
modifying and removing drawing entities using selection sets or other
ways of collecting drawing objects
.



Managing collections is typically done using common looping functions
(e.g. For,
ForEach

etc
) to step through collections of entities
.



Every AutoCAD
®

Drawing has a database that contains tables (e.g.
blocktable
,
layertable

etc
) and Dictionaries that can be retrieved as
arrays or as a generic List<T> which are both enumerable
.



Enumerable collections can be queried using LINQ.


©
2012
Autodesk

Querying the AutoCAD® Database

Examples using
foreach

to step through the drawings
layertable

and using a

LINQ
query with an anonymous method statement……


©
2012
Autodesk

Q
uery Syntax



LINQ query expressions are written in a declarative query syntax that
is similar to SQL statements and was introduced in C# 3.0.


LINQ Comprehension Query Syntax (or just Query Syntax)

var

layernames

=


from

oid

in
lt.Cast
<
ObjectId
>()


select

((
LayerTableRecord
)
tr.GetObject
(
oid
, OpenMode.ForRead,
false
)).Name;

LINQ Method Query Syntax (or DOT Syntax)

var

layernames

=


lt.Cast
<
ObjectId
>()


.Select<
ObjectId
,
string
> (
oid

=>


{


return ((
LayerTableRecord
)tr.GetObject(
oid
, OpenMode.ForRead,
false
)).Name;


}

©
2012
Autodesk

What are Generics
?


The term "generic" is a common term for


describing something that is not a brand name.




Medicine prescriptions may be filled


using a

generic


version
.



In programming

generic


can refer to a class that is not forced to any
specific Type
.



Generic classes are created to allow definition of collections without
specifying the actual types used.


List<
string
>
layernames

=
new

List<
string
>;

©
2012
Autodesk

Arrays, Generic List<T> and
IEnumerable



LINQ

extension methods for standard query
operators
add
query functionality to the existing
System.Collections.IEnumerable

and
System.Collections.Generic.IEnumerable
<T> types
.



The Array class provides methods for creating,
manipulating, searching and sorting arrays, it implements
the
IEnumerable

interface
.




The List<T> class represents a strongly typed list of
objects that can be accessed by index and is the generic
equivalent of the
ArrayList

class.



ArrayList

layernames

= new
ArrayList
();

©
2012
Autodesk

List<T> vs.
ArrayList
()...


A Generic List<T> is strongly typed so does not require BOXING and
UNBOXING when
enumerating the items.


UnBoxing

the opposite of boxing. A reference is retrieved to the value type (data fields)
contained within an object. The common language runtime first ensures that the reference
type variable is not null and that it refers to an object that is a boxed value of the desired
value type. If the types match, then a pointer to the value type contained inside the object
is returned.

Boxing is the process of converting a value type to a reference type. Memory is allocated
from the heap. The amount of memory allocated is the size

required by the value type plus
any additional overhead. The values are copied to the newly allocated heap memory. The
address of the object is returned as the reference type.

©
2012
Autodesk

IEnumerable
<T> and
IQueryable
<T> interfaces


The generic interface
IEnumerable
<T> is defined for generic types to
iterate the elements of a collection by exposing the enumerator, which
supports a simple iteration of a specific type.



Any data type that implements the
IEnumerable
<T> interface can
directly serve as a source for query expressions with LINQ
.




The
IQueryable
<T> interface is primarily used for query providers and
inherits the
IEnumerable
<T> interface so that a query can be
enumerated.


©
2012
Autodesk

Standard Query operators


Standard Query
Operators are the base of
LINQ
.



Extension methods that
implement the
IEnumerable
<T> interface

Operator Type

Operator Name

Aggregation

Aggregate, Average, Count, LongCount, Max, Min, Sum

Conversion

Cast, ConvertAll, OfType, ToArray, ToDictionary, ToList, ToLookup,
ToSequence

Element

DefaultIfEmpty
,
ElementAt
,
ElementAtOrDefault
, First,
FirstOrDefault
, Last,
LastOrDefault
, Single,
SingleOrDefault

Equality

EqualAll

Generation

Empty, Range, Repeat

Grouping

GroupBy

Joining

GroupJoin
, Join

Ordering

OrderBy, ThenBy, OrderByDescending, ThenByDescending,
Reverse

Partitioning

Skip,
SkipWhile
, Take,
TakeWhile

Quantifiers

All, Any, Contains

Restriction

Where

Selection

Select,
SelectMany

Set

Concat
, Distinct, Except, Intersect, Union

©
2012
Autodesk

LINQ Query Syntax Keywords

Clause


Description

from

Query syntax expressions must start with a ‘from’ clause. Specifies the data source and a range variable that
represents each element in the source.

where

Used in an expression to specify which elements will be returned. Applies a predicate to each element in the
source specified in the ‘from’ clause range variable.

select

Specifies the type of values in the returned sequence when the query is executed.

group

Returns a sequence that contains none or many items that match a specified key value.

into

Used to create an identifier that can serve as a reference to the results of a join, group or select clause.

orderby

Sorts query results in ascending or descending order based on the default comparer for the element type.

join

Joins two data sources based on an equality comparison between two specified matching criteria.

let

Introduces a range variable to store sub
-
expression results in a query expression.

in

Contextual keyword in a join clause.

on

Contextual keyword in a join clause.

equals

Contextual keyword in a join clause.

by

Contextual keyword in a group clause.

ascending

Contextual keyword in an orderby clause.

descending

Contextual keyword in an
orderby

clause.

©
2012
Autodesk

Anonymous
Types


LINQ is data driven programming which uses static structures instead of
objects, anonymous types are used to allow new structures to be defined

inline

.

Example creates an

inline


anonymous type with a property named

DBObj


returning
DBObjects

found to
dbObjCollection



var

dbObjCollection

=


from

oid

in

btr.Cast<
ObjectId
>()


select new


{




DBObj
= (
DBObject
)tr.GetObject(
oid
, OpenMode.ForRead,
false
)




}
;

var

dbTxt

=
from

obj

in

dbObjCollection



where

(
obj.DBObj.GetType
() ==
typeof
(
DBText
))


select

obj.DBObj
;

List<
DBText
>
dwgDBText

=
dbTxt.Cast
<
DBText
>().
ToList
()

©
2012
Autodesk

Anonymous Type

Var



The

var


keyword may remind you of less strongly typed
languages like VB6. Most languages now use strongly typed
objects
.



The

var


keyword tells the compiler to infer the type of the
variable from the static type of the expression used to initialize the
variable
.




LINQ determines the type at compile time and VB6 determined
the type at runtime.


var

dbTxt

=
from

obj

in

dbObjCollection



where

(
obj.DBObj.GetType
() ==
typeof
(
DBText
))


select

obj.DBObj
;

©
2012
Autodesk

Use

Var


or specify Type


Using Strongly
typing
:







Instead of:




The

var


local type inference is used to let the compiler determine the type.


IEnumerable
<
DBText
>
dbTxt

=


from

obj

in

dbObjCollection





where

(
obj.DBObj.GetType
() ==
typeof
(
DBText
))





select

(
DBText
)
obj.DBObj
;


The
result type of

DBText


is specified so the result type of the query must
be declared, this is a strongly type a query result.

var

dbTxt

=
from

obj

in

dbObjCollection


where

(
obj.DBObj.GetType
() ==
typeof
(
DBText
)


select

(
DBText
)
obj.DBObj
;

©
2012
Autodesk

Delegates and Anonymous
methods


Delegates are used to pass methods as arguments to other methods.


A class or a method can be created for using a delegate.


Anonymous methods were introduced in C# 2.0 which allows defining
anonymous (nameless) method to be called by a delegate.


delegate void
sampDelegate
(
string

s);

static public void

sampleDelegate
()

{


Editor

ed

=
AcadApp.DocumentManager.MdiActiveDocument.Editor
;


//anonymous delegate


sampDelegate

annonyDel

= delegate(
string

s) {
ed.WriteMessage
(s); };


annonyDel
("I am anonymous");



//lambda delegate


sampDelegate

lambdaDel

= (x) => {
ed.WriteMessage
(x); };


lambdaDel
("I am a Lambda expression");

}

©
2012
Autodesk

Anonymous method
example…

©
2012
Autodesk

Generic Delegate
System.Func


The generic delegate
System.Func

can be used to define a delegate
when needed without defining an explicit delegate type declaration.


Func
<
TResult
>();


Func
<TArg0,
TResult
>(TArg0 arg0);


Func
<TArg0, TArg1,
TResult
>(TArg0 arg0, TArg1 arg1);


Func
<TArg0, TArg1, TArg2,
TResult
>(TArg0 arg0, TArg1 arg1, TArg2 arg2);


Func
<TArg0, TArg1, TArg2, TArg3,
Tresult
>(
TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3);



The TArg0, TArg1, TArg2, and TArg3 parameters are argument types and the


TResult

parameter represents the result type.


Func
<
Point3d
,
bool
>
pointFilterX

= p => (
p.X

> 4.0);

©
2012
Autodesk

Generic Delegate System.Func
Example…

©
2012
Autodesk

Generic Delegate
System.Action


System.Action

is a set of predefined delegates that encapsulate up to 4
arguments with no return values…


static public void
actionSamp
()

{


Editor

ed

=
AcadApp.DocumentManager.MdiActiveDocument.Editor
;



Point3d

newpoint

=
new

Point3d
(4.0, 4.0, 0.0);


Action
<
Point3d
,
string
>
pointAction

= (p, s) =>
ed.WriteMessage
(s +
p.X.ToString
());




//execute action


pointAction
(
newpoint
, "value of X:");


}

©
2012
Autodesk

Predicate
Delegates


A predicate is a function that returns true or false and can be used to
filter the results of a query.


A predicate defines a set of criteria, and determines if a specified
object meets those criteria.


Predicates take advantage of the generic features introduced in the
.NET Framework 2.0.


Some of the methods that use an instance of the
System.Predicate

delegate to perform their tasks are: Exists, Find,
FindAll
,
FindIndex
,
FindLastIndex
,
FindLast
,
RemoveAll

and
TrueForAll
.


The best way of thinking about predicates is to think about them as
filters, that will evaluate to True or False.


©
2012
Autodesk

Predicates
Examples…

Example searches for layers containing the string

Layer


in the delegate
used as the predicate:


©
2012
Autodesk

Lambda Expressions


Query operators provide functionality to perform filtering, projection,
or extraction and build on the concept of lambda expressions
.



Lambda expressions are an evolution of anonymous methods
introduced in .NET 2.0
.



The

=>


symbol is used in lambda statements stating that the
defined object

goes into


the expression…


Func
<
Point3d
,
bool
>
pointFilterX

= p => (
p.X

> 4.0);

Func
<
Point3d
,
bool
>
pointFilterY

= p => (
p.Y

> 4.0);

MinX

=
objExtents.Min
<
Extents3d
>(
ext

=>
ext.MinPoint.X
);

MinY

=
objExtents.Min
<
Extents3d
>(
ext

=>
ext.MinPoint.Y
);

MinZ

=
objExtents.Min
<
Extents3d
>(
ext

=>
ext.MinPoint.Z
);

©
2012
Autodesk

Lambda
Expressions


Nested lambda example (

ent


of type Entity can be used in second
inline lambda statement)
:



Lambda expressions used in delegates
:





Expressions or statement blocks can be contained in Lambda
expressions.


.
Where
<Entity>(
ent

=>
layernames.Any
<
string
>(lay => lay ==
ent.Layer
))

string
[] parts = { "Bolt", "Nut", "
Flange","Pipe
", "Bar", "Cylinder"};

Func
<
string
,
bool
>
filt

= s =>
s.
Length

> 5;

Func
<
string
,
string
>
val

= s => s;

Func
<
string
,
string
>
sel

= s =>
s.
ToUpper
();

IEnumerable
<
string
> query =
parts.
Where
(
filt
).
OrderBy
(
val
).
Select
(
sel
);

a => 3.1416 * a // Expression

a => {
return

3.1416 * a;} // Statement

©
2012
Autodesk

Lambda Expressions


Delegates and lambda expressions are equivalent.


Func
<
int
>
funcDelegate

=
delegate
(
int

a)


{


return

a * 3.1416;


};


Func
<
int
> lambda = a => a * 3.1416;

©
2012
Autodesk

Lambda
Expressions…

©
2012
Autodesk

Expression
Trees


LINQ provides a simple syntax for translating code into a data structure
called an expression tree
.



The
System.Linq.Expressions

namespace defines a generic type,
Expression<T>, where T is the type of the delegate that defines the
expression's signature
.



Expression trees are used for creating LINQ Providers to extend
querying to multiple data structures.


©
2012
Autodesk

Expression
Trees…


Expression trees are created in
-
memory

out of lambda expressions
and then allow manipulation or inspection of the expression as data.



©
2012
Autodesk

Object Initializers


A feature added in C# 3.0 is the syntax for object initializers
.







Allow initializing an object by creating the object instance
.



Assign values to one or more properties in a single sentence
.



Initialize a collection with a set of values to add in a single expression
similar to how it is done with arrays.


var

dbObjCollection

=


from

oid

in

btr.Cast<
ObjectId
>()


select

new


{


DBObj = (
DBObject
)tr.GetObject(
oid
, OpenMode.ForRead,
false
)

};

©
2012
Autodesk

Object Initializers


Anonymous types can be populated using object initializers.


var

dwgInfo

=
new

{


Description = "New Drawing",


DrawnBY

= "James",


Date = "
11/27/2012"
,


DwgNumber

= "123456",


RevisionNo

= "A"


};


©
2012
Autodesk

Object
Initializers…


This example illustrates using object initializers to set the values to
instances of the class and then adding those objects to a generic list.


©
2012
Autodesk

Extension
Methods


Allow the creation of methods on an existing

Type


creating the
illusion of new methods.


Add methods to a class compiled outside of the current assembly that
can not be changed.


With extension methods developers can augment the

Type


with new
methods to provide their own methods.


Extension methods are defined in static classes as static methods.


In C#, extension methods are indicated by the

this


modifier which
must be applied to the first parameter of the extension method.


©
2012
Autodesk

Extension Methods


Extension methods are resolved at compile
-
time.


LINQ standard query operators are extension methods in the
System.Linq

namespace, these extension methods extend
IEnumerable
<T> and
IQueryable
<T>.


Most of the standard query operators extend from the
IEnumerable
<T>
interface, these types will get the standard query operators by adding
the using statement

using

System.Linq
;


in C#.



Extension methods show up in
Intellisense


©
2012
Autodesk

Extension
Methods…


The type of the first parameter of an extension method indicates what
type the extension applies to.


©
2012
Autodesk

Deferred Query Evaluation


LINQ standard query operators return elements when enumerated not
when declared.


Operators do no work UNTIL the query requests an element then
suspends until the next element is requested.


Deferred evaluation allows queries to be kept as
IEnumerable
<T>
based values that can be evaluated multiple times, each time yielding
potentially different results.


A query can be enumerated immediately, using
ToList
() or
ToArray
()
which both will enumerate the entire sequence returning a result.



©
2012
Autodesk

Deferred Query
Evaluation…


Example uses one of the previous examples to get text entities then
modifies the

Last


text entity found and runs the query again…


©
2012
Autodesk

.
NET Dynamic Language
Runtime…


The Dynamic Language Runtime (DLR) is used to implement dynamic
languages like Python and Ruby on the .NET Framework
.


In Visual Studio 2010 C# a new type of 'dynamic' was introduced.


No
Intellisense
.

©
2012
Autodesk

Thanks for Attending…

©
2012
Autodesk

Autodesk, AutoCAD* [*if/when mentioned in the pertinent material, followed by an alphabetical list of all other trademarks me
nti
oned in the material] are registered trademarks or trademarks of Autodesk, Inc., and/or its subsidiaries and/or affiliates in

th
e USA and/or other countries.
All
other brand names, product names, or trademarks belong to their respective holders. Autodesk reserves the right to alter prod
uct

and
services offerings, and specifications and pricing at any time without notice, and is not responsible for typographical or gr
aph
ical errors that may appear in this document. ©
2012
Autodesk, Inc. All rights reserved.