public List <KeyValuePair <string, string> > Morph(object args)
            {
                // Transform the args into a bag of key-value strings.
                var outputArgs = new List <KeyValuePair <string, string> >();

                if (args != null)
                {
                    if (!_noImplicitTransforms)
                    {
                        // given the type, fetch the implicit transforms for that type and put it in the implicitTransforms variable.
                        Type          argType = args.GetType();
                        TransformSpec implicitTransforms;

                        // First check the one-element cache _firstImplicitTransformsEntry
                        ImplicitTransformEntry cacheEntry = _firstImplicitTransformsEntry;
                        if (cacheEntry != null && cacheEntry.Type == argType)
                        {
                            implicitTransforms = cacheEntry.Transforms;     // Yeah we hit the cache.
                        }
                        else if (cacheEntry == null)
                        {
                            // _firstImplicitTransformsEntry is empty, we should fill it.
                            // Note that it is OK that two threads may race and both call MakeImplicitTransforms on their own
                            // (that is we don't expect exactly once initialization of _firstImplicitTransformsEntry)
                            implicitTransforms = MakeImplicitTransforms(argType);
                            Interlocked.CompareExchange(ref _firstImplicitTransformsEntry,
                                                        new ImplicitTransformEntry()
                            {
                                Type = argType, Transforms = implicitTransforms
                            }, null);
                        }
                        else
                        {
                            // This should only happen when you are wildcarding your events (reasonably rare).
                            // In that case you will probably need many types
                            // Note currently we don't limit the cache size, but it is limited by the number of
                            // distinct types of objects passed to DiagnosticSource.Write.
                            if (_implicitTransformsTable == null)
                            {
                                Interlocked.CompareExchange(ref _implicitTransformsTable,
                                                            new ConcurrentDictionary <Type, TransformSpec>(1, 8), null);
                            }
                            implicitTransforms = _implicitTransformsTable.GetOrAdd(argType, type => MakeImplicitTransforms(type));
                        }

                        // implicitTransformas now fetched from cache or constructed, use it to Fetch all the implicit fields.
                        if (implicitTransforms != null)
                        {
                            for (TransformSpec serializableArg = implicitTransforms; serializableArg != null; serializableArg = serializableArg.Next)
                            {
                                outputArgs.Add(serializableArg.Morph(args));
                            }
                        }
                    }

                    if (_explicitTransforms != null)
                    {
                        for (var explicitTransform = _explicitTransforms; explicitTransform != null; explicitTransform = explicitTransform.Next)
                        {
                            var keyValue = explicitTransform.Morph(args);
                            if (keyValue.Value != null)
                            {
                                outputArgs.Add(keyValue);
                            }
                        }
                    }
                }
                return(outputArgs);
            }