Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / clr / src / BCL / System / Runtime / Serialization / Formatters / Binary / BinaryObjectWriter.cs / 1 / BinaryObjectWriter.cs
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: ObjectWriter
**
**
** Purpose: Serializes an object graph into XML in SOAP format
**
**
===========================================================*/
namespace System.Runtime.Serialization.Formatters.Binary
{
using System;
using System.IO;
using System.Reflection;
using System.Reflection.Cache;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Security;
using System.Diagnostics;
using System.Globalization;
internal sealed class ObjectWriter
{
private Queue m_objectQueue;
private ObjectIDGenerator m_idGenerator;
private int m_currentId;
private ISurrogateSelector m_surrogates;
private StreamingContext m_context;
private __BinaryWriter serWriter;
private SerializationObjectManager m_objectManager;
private long topId;
private String topName = null;
private Header[] headers;
private InternalFE formatterEnums;
private SerObjectInfoInit serObjectInfoInit = null;
private IFormatterConverter m_formatterConverter;
internal Object[] crossAppDomainArray = null;
internal ArrayList internalCrossAppDomainArray = null;
// XMLObjectWriter Constructor
internal ObjectWriter(ISurrogateSelector selector, StreamingContext context,InternalFE formatterEnums)
{
m_currentId = 1;
m_surrogates = selector;
m_context = context;
this.formatterEnums = formatterEnums;
m_objectManager = new SerializationObjectManager(context);
SerTrace.InfoLog(
formatterEnums.FEtypeFormat +" "+
((Enum)formatterEnums.FEserializerTypeEnum));
}
// Commences the process of serializing the entire graph.
// initialize the graph walker.
internal void Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, bool fCheck)
{
SerTrace.Log( this, "Serialize Entry 2 ",graph,((headers == null)?" no headers ": "headers "));
if (fCheck)
{
CodeAccessPermission.DemandInternal(PermissionType.SecuritySerialization);
}
if (graph == null)
throw new ArgumentNullException("graph",Environment.GetResourceString("ArgumentNull_Graph"));
if (serWriter == null)
throw new ArgumentNullException("serWriter",String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentNull_WithParamName"), "serWriter"));
this.serWriter = serWriter;
this.headers = inHeaders;
SerTrace.Log( this, "Serialize New SerializedTypeTable");
serWriter.WriteBegin();
long headerId = 0;
Object obj;
long objectId;
bool isNew;
bool bMethodCall = false;
bool bMethodReturn = false;
// Special case IMethodCallMessage and IMethodReturnMessage for performance
IMethodCallMessage mess = graph as IMethodCallMessage;
if (mess != null)
{
bMethodCall = true;
graph = WriteMethodCall(mess);
}
else
{
IMethodReturnMessage mr = graph as IMethodReturnMessage;
if (mr != null)
{
bMethodReturn = true;
graph = WriteMethodReturn(mr);
}
}
if (graph == null)
{
WriteSerializedStreamHeader(topId, headerId);
if (bMethodCall)
serWriter.WriteMethodCall();
else if (bMethodReturn)
serWriter.WriteMethodReturn();
serWriter.WriteSerializationHeaderEnd();
serWriter.WriteEnd();
return;
}
// allocations if methodCall or methodResponse and no graph
m_idGenerator = new ObjectIDGenerator();
m_objectQueue = new Queue();
m_formatterConverter = new FormatterConverter();
serObjectInfoInit = new SerObjectInfoInit();
topId = InternalGetId(graph, false, null, out isNew);
if (headers != null)
headerId = InternalGetId(headers, false, null, out isNew);
else
headerId = -1;
WriteSerializedStreamHeader(topId, headerId);
if (bMethodCall)
serWriter.WriteMethodCall();
else if (bMethodReturn)
serWriter.WriteMethodReturn();
SerTrace.Log( this, "Serialize Schedule 0");
// Write out SerializedStream header
if ((headers != null) && (headers.Length > 0))
m_objectQueue.Enqueue(headers);
if (graph != null)
m_objectQueue.Enqueue(graph);
while ((obj = GetNext(out objectId))!=null)
{
SerTrace.Log( this, "Serialize GetNext ",obj);
WriteObjectInfo objectInfo = null;
// GetNext will return either an object or a WriteObjectInfo.
// A WriteObjectInfo is returned if this object was member of another object
if (obj is WriteObjectInfo)
{
SerTrace.Log( this, "Serialize GetNext recognizes WriteObjectInfo");
objectInfo = (WriteObjectInfo)obj;
}
else
{
objectInfo = WriteObjectInfo.Serialize(obj, m_surrogates, m_context, serObjectInfoInit, m_formatterConverter, this);
objectInfo.assemId = GetAssemblyId(objectInfo);
}
objectInfo.objectId = objectId;
NameInfo typeNameInfo = TypeToNameInfo(objectInfo);
Write(objectInfo, typeNameInfo, typeNameInfo);
PutNameInfo(typeNameInfo);
objectInfo.ObjectEnd();
}
serWriter.WriteSerializationHeaderEnd();
serWriter.WriteEnd();
// Invoke OnSerialized Event
m_objectManager.RaiseOnSerializedEvent();
SerTrace.Log( this, "Serialize Exit ");
}
private Object[] WriteMethodCall(IMethodCallMessage mcm)
{
// In header
String uri = mcm.Uri;
String methodName = mcm.MethodName;
String typeName = mcm.TypeName;
// Optional
Object methodSignature = null;
Object callContext = null;
Object[] properties = null;
// instantiation args
Type[] instArgs = null;
if (mcm.MethodBase.IsGenericMethod)
instArgs = mcm.MethodBase.GetGenericArguments();
// args
Object[] args = mcm.Args;
IInternalMessage iim = mcm as IInternalMessage;
// user properties (everything but special entries)
if ((iim == null) || iim.HasProperties())
properties = StoreUserPropertiesForMethodMessage(mcm);
// handle method signature
if (mcm.MethodSignature != null && RemotingServices.IsMethodOverloaded(mcm))
methodSignature = mcm.MethodSignature;
// handle call context
LogicalCallContext lcc = mcm.LogicalCallContext;
if (lcc == null)
{
callContext = null;
}
else if (lcc.HasInfo)
callContext = lcc;
else
{
// just smuggle the call id string
callContext = lcc.RemotingData.LogicalCallID;
}
return serWriter.WriteCallArray(uri, methodName, typeName, instArgs, args, methodSignature, callContext, properties);
}
private Object[] WriteMethodReturn(IMethodReturnMessage mrm)
{
Object returnValue = mrm.ReturnValue;
Object[] args = mrm.Args;
Exception exception = mrm.Exception;
Object callContext;
Object[] properties = null;
ReturnMessage retMsg = mrm as ReturnMessage;
// user properties (everything but special entries)
if ((retMsg == null) || retMsg.HasProperties())
properties = StoreUserPropertiesForMethodMessage(mrm);
// handle call context
LogicalCallContext lcc = mrm.LogicalCallContext;
if (lcc == null)
{
callContext = null;
}
else if (lcc.HasInfo)
callContext = lcc;
else
{
// just smuggle the call id string
callContext = lcc.RemotingData.LogicalCallID;
}
return serWriter.WriteReturnArray(returnValue, args, exception, callContext, properties);
}
// returns number of entries added to argsToSerialize
private static Object[] StoreUserPropertiesForMethodMessage(IMethodMessage msg)
{
ArrayList argsToSerialize = null;
IDictionary properties = msg.Properties;
if (properties == null)
return null;
MessageDictionary dict = properties as MessageDictionary;
if (dict != null)
{
if (dict.HasUserData())
{
int co = 0;
foreach (DictionaryEntry entry in dict.InternalDictionary)
{
if (argsToSerialize == null)
argsToSerialize = new ArrayList();
argsToSerialize.Add(entry);
co++;
}
return argsToSerialize.ToArray();
}
else
{
return null;
}
}
else
{
// <
int co = 0;
foreach (DictionaryEntry entry in properties)
{
if (argsToSerialize == null)
argsToSerialize = new ArrayList();
argsToSerialize.Add(entry);
co++;
}
if (argsToSerialize != null)
return argsToSerialize.ToArray();
else
return null;
}
} // StoreUserPropertiesForMethodMessage
internal SerializationObjectManager ObjectManager
{
get { return m_objectManager; }
}
// Writes a given object to the stream.
private void Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
{
#if _DEBUG
SerTrace.Log( this, "Write 1 Entry objectInfo ",objectInfo,", memberNameInfo ",memberNameInfo,", typeNameInfo ",typeNameInfo);
memberNameInfo.Dump("Write memberNameInfo");
typeNameInfo.Dump("Write typeNameInfo");
#endif
Object obj = objectInfo.obj;
if (obj==null)
throw new ArgumentNullException("objectInfo.obj", Environment.GetResourceString("ArgumentNull_Obj"));
SerTrace.Log( this, "Write 1 objectInfo obj ",objectInfo.obj," objectId ", objectInfo.objectId, " objectType ", objectInfo.objectType);
Type objType = objectInfo.objectType;
long objectId = objectInfo.objectId;
SerTrace.Log( this, "Write 1 ",obj," ObjectId ",objectId);
if (objType == Converter.typeofString)
{
// Top level String
memberNameInfo.NIobjectId = objectId;
serWriter.WriteObjectString((int)objectId, obj.ToString());
}
else
{
if (objectInfo.isArray)
{
WriteArray(objectInfo, memberNameInfo, null);
}
else
{
String[] memberNames;
Type[] memberTypes;
Object[] memberData;
objectInfo.GetMemberInfo(out memberNames, out memberTypes, out memberData);
// Only Binary needs to transmit types for ISerializable because the binary formatter transmits the types in URT format.
// Soap transmits all types as strings, so it is up to the ISerializable object to convert the string back to its URT type
if (objectInfo.isSi || CheckTypeFormat(formatterEnums.FEtypeFormat, FormatterTypeStyle.TypesAlways))
{
SerTrace.Log( this, "Write 1 TransmitOnObject ");
memberNameInfo.NItransmitTypeOnObject = true;
memberNameInfo.NIisParentTypeOnObject = true;
typeNameInfo.NItransmitTypeOnObject = true;
typeNameInfo.NIisParentTypeOnObject = true;
}
WriteObjectInfo[] memberObjectInfos = new WriteObjectInfo[memberNames.Length];
// Get assembly information
// Binary Serializer, assembly names need to be
// written before objects are referenced.
// GetAssemId here will write out the
// assemblyStrings at the right Binary
// Serialization object boundary.
for (int i=0; i 0)
{
// Array as object
SerTrace.Log( this, "WriteMembers Schedule 3");
memberNameInfo.NIobjectId = arrayId;
WriteObjectRef(memberNameInfo, arrayId);
}
else
{
// Nested Array
serWriter.WriteMemberNested(memberNameInfo);
memberObjectInfo.objectId = arrayId;
memberNameInfo.NIobjectId = arrayId;
WriteArray(memberObjectInfo, memberNameInfo, memberObjectInfo);
objectInfo.ObjectEnd();
}
SerTrace.Log( this, "WriteMembers Array Exit ");
return;
}
if (!WriteKnownValueClass(memberNameInfo, memberTypeNameInfo, memberData))
{
SerTrace.Log( this, "WriteMembers Object ",memberData);
#if false
// Value or NO_ID, need to explicitly check for IsValue because a top level
// value class has an objectId of 1
/*
if (memberType.IsValueType)
{
SerTrace.Log( this, "WriteMembers Value Type or NO_ID parameter");
bool isNew;
memberObjectInfo.objectId = InternalGetId(outObj, assignUniqueIdToValueType, memberType, out isNew) ;
NameInfo newTypeNameInfo = TypeToNameInfo(memberObjectInfo);
newTypeNameInfo.NIobjectId = memberObjectInfo.objectId;
Write( memberObjectInfo, memberNameInfo, newTypeNameInfo);
PutNameInfo(newTypeNameInfo);
memberObjectInfo.ObjectEnd();
}
else
*/
#endif
{
SerTrace.Log( this, "WriteMembers Schedule 4 ", outType, " memberInfo ",memberObjectInfo);
if (outType == null)
outType = GetType(outObj);
long memberObjectId = Schedule(outObj, assignUniqueIdToValueType, outType, memberObjectInfo);
if (memberObjectId < 0)
{
// Nested object
SerTrace.Log( this, "WriteMembers Nesting");
memberObjectInfo.objectId = memberObjectId;
NameInfo newTypeNameInfo = TypeToNameInfo(memberObjectInfo);
newTypeNameInfo.NIobjectId = memberObjectId;
Write(memberObjectInfo, memberNameInfo, newTypeNameInfo);
PutNameInfo(newTypeNameInfo);
memberObjectInfo.ObjectEnd();
}
else
{
// Object reference
memberNameInfo.NIobjectId = memberObjectId;
WriteObjectRef(memberNameInfo, memberObjectId);
}
}
}
SerTrace.Log( this, "WriteMembers Exit ");
}
// Writes out an array
private void WriteArray(WriteObjectInfo objectInfo, NameInfo memberNameInfo, WriteObjectInfo memberObjectInfo)
{
SerTrace.Log( this, "WriteArray Entry ",objectInfo.obj," ",objectInfo.objectId);
bool isAllocatedMemberNameInfo = false;
if (memberNameInfo == null)
{
memberNameInfo = TypeToNameInfo(objectInfo);
isAllocatedMemberNameInfo = true;
}
memberNameInfo.NIisArray = true;
long objectId = objectInfo.objectId;
memberNameInfo.NIobjectId = objectInfo.objectId;
// Get array type
System.Array array = (System.Array)objectInfo.obj;
//Type arrayType = array.GetType();
Type arrayType = objectInfo.objectType;
// Get type of array element
Type arrayElemType = arrayType.GetElementType();
WriteObjectInfo arrayElemObjectInfo = null;
if (!arrayElemType.IsPrimitive)
{
arrayElemObjectInfo = WriteObjectInfo.Serialize(arrayElemType, m_surrogates, m_context, serObjectInfoInit, m_formatterConverter);
arrayElemObjectInfo.assemId = GetAssemblyId(arrayElemObjectInfo);
}
NameInfo arrayElemTypeNameInfo = null;
if (arrayElemObjectInfo == null)
arrayElemTypeNameInfo = TypeToNameInfo(arrayElemType);
else
arrayElemTypeNameInfo = TypeToNameInfo(arrayElemObjectInfo);
arrayElemTypeNameInfo.NIisArray = arrayElemTypeNameInfo.NItype.IsArray;
NameInfo arrayNameInfo = memberNameInfo;
arrayNameInfo.NIobjectId = objectId;
arrayNameInfo.NIisArray = true;
arrayElemTypeNameInfo.NIobjectId = objectId;
arrayElemTypeNameInfo.NItransmitTypeOnMember = memberNameInfo.NItransmitTypeOnMember;
arrayElemTypeNameInfo.NItransmitTypeOnObject = memberNameInfo.NItransmitTypeOnObject;
arrayElemTypeNameInfo.NIisParentTypeOnObject = memberNameInfo.NIisParentTypeOnObject;
// Get rank and length information
int rank = array.Rank;
int[] lengthA = new int[rank];
int[] lowerBoundA = new int[rank];
int[] upperBoundA = new int[rank];
for (int i=0; i-1; irank--)
{
// Find the current or lower dimension which can be incremented.
if (currentA[irank] < maxA[irank]-1)
{
// The current dimension is at maximum. Increase the next lower dimension by 1
currentA[irank]++;
if (irank < rank-1)
{
// The current dimension and higher dimensions are zeroed.
for (int i = irank+1; i 0)
{
if (objectInfo == null)
m_objectQueue.Enqueue(obj);
else
m_objectQueue.Enqueue(objectInfo);
}
SerTrace.Log( this, "Schedule Exit, id: ",id," isNew: ",isNew);
return id;
}
// Determines if a type is a primitive type, if it is it is written
private bool WriteKnownValueClass(NameInfo memberNameInfo, NameInfo typeNameInfo, Object data)
{
#if _DEBUG
SerTrace.Log( this, "WriteKnownValueClass Entry ",typeNameInfo.NIname," ",data," ",memberNameInfo.NIname);
memberNameInfo.Dump("WriteKnownValueClass memberNameInfo");
typeNameInfo.Dump("WriteKnownValueClass typeNameInfo");
#endif
if (typeNameInfo.NItype == Converter.typeofString)
{
WriteString(memberNameInfo, typeNameInfo, data);
}
else
{
if (typeNameInfo.NIprimitiveTypeEnum == InternalPrimitiveTypeE.Invalid)
{
SerTrace.Log( this, "WriteKnownValueClass Exit false");
return false;
}
else
{
if (typeNameInfo.NIisArray) // null if an array
serWriter.WriteItem(memberNameInfo, typeNameInfo, data);
else
{
serWriter.WriteMember(memberNameInfo, typeNameInfo, data);
}
}
}
SerTrace.Log( this, "WriteKnownValueClass Exit true");
return true;
}
// Writes an object reference to the stream.
private void WriteObjectRef(NameInfo nameInfo, long objectId)
{
SerTrace.Log( this, "WriteObjectRef Entry ",nameInfo.NIname," ",objectId);
serWriter.WriteMemberObjectRef(nameInfo, (int)objectId);
SerTrace.Log( this, "WriteObjectRef Exit ");
}
// Writes a string into the XML stream
private void WriteString(NameInfo memberNameInfo, NameInfo typeNameInfo, Object stringObject)
{
SerTrace.Log( this, "WriteString stringObject ",stringObject," memberName ",memberNameInfo.NIname);
bool isFirstTime = true;
long stringId = -1;
if (!CheckTypeFormat(formatterEnums.FEtypeFormat, FormatterTypeStyle.XsdString))
stringId= InternalGetId(stringObject, false, null, out isFirstTime);
typeNameInfo.NIobjectId = stringId;
SerTrace.Log( this, "WriteString stringId ",stringId," isFirstTime ",isFirstTime);
if ((isFirstTime) || (stringId < 0))
serWriter.WriteMemberString(memberNameInfo, typeNameInfo, (String)stringObject);
else
WriteObjectRef(memberNameInfo, stringId);
}
// Writes a null member into the stream
private bool CheckForNull(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo, Object data)
{
#if _DEBUG
SerTrace.Log( this, "CheckForNull Entry data ",Util.PString(data),", memberType ",Util.PString(typeNameInfo.NItype));
#endif
bool isNull = false;
if (data == null) // || Convert.IsDBNull(data)
isNull = true;
// Optimization, Null members are only written for Binary
if ((isNull) && (((formatterEnums.FEserializerTypeEnum == InternalSerializerTypeE.Binary)) ||
memberNameInfo.NIisArrayItem ||
memberNameInfo.NItransmitTypeOnObject ||
memberNameInfo.NItransmitTypeOnMember ||
objectInfo.isSi ||
(CheckTypeFormat(formatterEnums.FEtypeFormat, FormatterTypeStyle.TypesAlways))))
{
SerTrace.Log( this, "CheckForNull Write");
if (typeNameInfo.NIisArrayItem)
{
if (typeNameInfo.NIarrayEnum == InternalArrayTypeE.Single)
serWriter.WriteDelayedNullItem();
else
serWriter.WriteNullItem(memberNameInfo, typeNameInfo);
}
else
serWriter.WriteNullMember(memberNameInfo, typeNameInfo);
}
SerTrace.Log( this, "CheckForNull Exit ",isNull);
return isNull;
}
// Writes the SerializedStreamHeader
private void WriteSerializedStreamHeader(long topId, long headerId)
{
serWriter.WriteSerializationHeader((int)topId, (int)headerId, 1, 0);
}
// Transforms a type to the serialized string form. URT Primitive types are converted to XMLData Types
private NameInfo TypeToNameInfo(Type type, WriteObjectInfo objectInfo, InternalPrimitiveTypeE code, NameInfo nameInfo)
{
SerTrace.Log( this, "TypeToNameInfo Entry type ",type,", objectInfo ",objectInfo,", code ", ((Enum)code).ToString());
if (nameInfo == null)
nameInfo = GetNameInfo();
else
nameInfo.Init();
if (code == InternalPrimitiveTypeE.Invalid)
{
if (objectInfo != null)
{
nameInfo.NIname = objectInfo.GetTypeFullName();
nameInfo.NIassemId = objectInfo.assemId;
}
}
nameInfo.NIprimitiveTypeEnum = code;
nameInfo.NItype = type;
SerTrace.Log( this, "TypeToNameInfo Exit ",type, " typeName "+nameInfo.NIname);
return nameInfo;
}
private NameInfo TypeToNameInfo(Type type)
{
return TypeToNameInfo(type, null, ToCode(type), null);
}
private NameInfo TypeToNameInfo(WriteObjectInfo objectInfo)
{
return TypeToNameInfo(objectInfo.objectType, objectInfo, ToCode(objectInfo.objectType), null);
}
private NameInfo TypeToNameInfo(WriteObjectInfo objectInfo, NameInfo nameInfo)
{
return TypeToNameInfo(objectInfo.objectType, objectInfo, ToCode(objectInfo.objectType), nameInfo);
}
private void TypeToNameInfo(Type type, NameInfo nameInfo)
{
TypeToNameInfo(type, null, ToCode(type), nameInfo);
}
private NameInfo MemberToNameInfo(String name)
{
NameInfo memberNameInfo = GetNameInfo();
memberNameInfo.NIname = name;
return memberNameInfo;
}
Type previousType = null;
InternalPrimitiveTypeE previousCode = InternalPrimitiveTypeE.Invalid;
internal InternalPrimitiveTypeE ToCode(Type type)
{
if (previousType == type)
{
return previousCode;
}
else
{
InternalPrimitiveTypeE code = Converter.ToCode(type);
if (code != InternalPrimitiveTypeE.Invalid)
{
previousType = type;
previousCode = code;
}
return code;
}
}
private Hashtable assemblyToIdTable = null;
private long GetAssemblyId(WriteObjectInfo objectInfo)
{
//use objectInfo to get assembly string with new criteria
SerTrace.Log( this, "GetAssemblyId Entry ",objectInfo.objectType," isSi ",objectInfo.isSi);
if (assemblyToIdTable == null)
assemblyToIdTable = new Hashtable(5);
long assemId = 0;
bool isNew = false;
String assemblyString = objectInfo.GetAssemblyString();
String serializedAssemblyString = assemblyString;
if (assemblyString.Length == 0)
{
assemId = 0;
}
else if (assemblyString.Equals(Converter.urtAssemblyString))
{
// Urt type is an assemId of 0. No assemblyString needs
// to be sent
SerTrace.Log( this, "GetAssemblyId urt Assembly String ");
assemId = 0;
}
else
{
// Assembly needs to be sent
// Need to prefix assembly string to separate the string names from the
// assemblyName string names. That is a string can have the same value
// as an assemblyNameString, but it is serialized differently
if (assemblyToIdTable.ContainsKey(assemblyString))
{
assemId = (long)assemblyToIdTable[assemblyString];
isNew = false;
}
else
{
assemId = InternalGetId("___AssemblyString___"+assemblyString, false, null, out isNew);
assemblyToIdTable[assemblyString] = assemId;
}
serWriter.WriteAssembly(objectInfo.GetTypeFullName(), objectInfo.objectType, serializedAssemblyString, (int)assemId, isNew, false);
}
SerTrace.Log( this, "GetAssemblyId Exit id ",assemId," isNew ",isNew," assemblyString ",serializedAssemblyString);
return assemId;
}
private Type GetType(Object obj)
{
Type type = null;
if (RemotingServices.IsTransparentProxy(obj))
type = Converter.typeofMarshalByRefObject;
else
type = obj.GetType();
return type;
}
private SerStack niPool = new SerStack("NameInfo Pool");
private NameInfo GetNameInfo()
{
NameInfo nameInfo = null;
if (!niPool.IsEmpty())
{
nameInfo = (NameInfo)niPool.Pop();
nameInfo.Init();
}
else
nameInfo = new NameInfo();
return nameInfo;
}
private bool CheckTypeFormat(FormatterTypeStyle test, FormatterTypeStyle want)
{
return(test & want) == want;
}
private void PutNameInfo(NameInfo nameInfo)
{
niPool.Push(nameInfo);
}
}
}
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- GroupBoxAutomationPeer.cs
- CodeMethodReturnStatement.cs
- TemplateBamlTreeBuilder.cs
- GeometryDrawing.cs
- SqlClientMetaDataCollectionNames.cs
- CompilationSection.cs
- MobileSysDescriptionAttribute.cs
- GradientBrush.cs
- Missing.cs
- ValueQuery.cs
- Base64Decoder.cs
- MimePart.cs
- TimeSpanMinutesOrInfiniteConverter.cs
- AbsoluteQuery.cs
- DocumentViewerAutomationPeer.cs
- ValueSerializer.cs
- IProvider.cs
- AsymmetricSignatureFormatter.cs
- VScrollProperties.cs
- AssociatedControlConverter.cs
- BigInt.cs
- Stack.cs
- SearchForVirtualItemEventArgs.cs
- ReadOnlyMetadataCollection.cs
- ImageConverter.cs
- ColorAnimation.cs
- BindingMemberInfo.cs
- DetailsViewCommandEventArgs.cs
- control.ime.cs
- HtmlTableCellCollection.cs
- TableColumnCollectionInternal.cs
- ExpressionBindings.cs
- MasterPageParser.cs
- VScrollBar.cs
- FontUnitConverter.cs
- OrderingInfo.cs
- DoubleCollectionConverter.cs
- AtomEntry.cs
- TypedTableBase.cs
- PropertyPathWorker.cs
- CssTextWriter.cs
- dtdvalidator.cs
- PageFunction.cs
- ConfigurationCollectionAttribute.cs
- FastPropertyAccessor.cs
- oledbmetadatacolumnnames.cs
- Encoding.cs
- EdmToObjectNamespaceMap.cs
- CompositionCommandSet.cs
- PrimitiveRenderer.cs
- RadioButtonRenderer.cs
- TypedReference.cs
- ChannelServices.cs
- CompleteWizardStep.cs
- RegistrationServices.cs
- RegexTypeEditor.cs
- DbConnectionPoolIdentity.cs
- AdapterDictionary.cs
- TdsParserHelperClasses.cs
- WithStatement.cs
- AutomationElementCollection.cs
- SubtreeProcessor.cs
- XmlWrappingWriter.cs
- CSharpCodeProvider.cs
- SubclassTypeValidator.cs
- TypeListConverter.cs
- DataStreamFromComStream.cs
- XmlNodeWriter.cs
- WebRequestModuleElementCollection.cs
- ImpersonationContext.cs
- ErrorEventArgs.cs
- TrackingParameters.cs
- RegexRunner.cs
- EncoderFallback.cs
- JapaneseCalendar.cs
- HtmlInputHidden.cs
- OperationPickerDialog.designer.cs
- Site.cs
- BitmapImage.cs
- ResourcesGenerator.cs
- EntityDesignerDataSourceView.cs
- BaseParaClient.cs
- IgnoreDeviceFilterElementCollection.cs
- AssociationTypeEmitter.cs
- RegisteredDisposeScript.cs
- ConnectionsZoneAutoFormat.cs
- TableColumnCollectionInternal.cs
- WebPartConnectionsCloseVerb.cs
- DummyDataSource.cs
- GlobalProxySelection.cs
- SimplePropertyEntry.cs
- ViewPort3D.cs
- SpellerInterop.cs
- DeleteStoreRequest.cs
- BamlRecordWriter.cs
- FieldNameLookup.cs
- Column.cs
- PageSettings.cs
- Rijndael.cs
- WindowsContainer.cs