Click here to Skip to main content
15,886,689 members
Articles / Programming Languages / C#

UniversalSerializer

Rate me:
Please Sign up or sign in to vote.
4.97/5 (108 votes)
15 Apr 2018Ms-RL31 min read 258K   4K   299  
An universal and easy serialization library for .NET and .NET Core.

// Copyright Christophe Bertrand.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace UniversalSerializerLib3
{
	internal class ParsedAssemblyQualifiedName
	{
		internal Lazy<AssemblyName> AssemblyNameDescriptor;
		internal Lazy<Type> FoundType;
		internal readonly string AssemblyDescriptionString;
		internal readonly string TypeName;
		internal readonly string ShortAssemblyName;
		internal readonly string Version;
		internal readonly string Culture;
		internal readonly string internalKeyToken;
		internal readonly List<ParsedAssemblyQualifiedName> GenericParameters = new List<ParsedAssemblyQualifiedName>();
		internal readonly Lazy<string> CSharpStyleName;
		internal readonly Lazy<string> VBNetStyleName;

		internal ParsedAssemblyQualifiedName(string AssemblyQualifiedName)
		{
			int index = -1;
			block rootBlock = new block();
			{
				int bcount = 0;
				block currentBlock = rootBlock;
				for (int i = 0; i < AssemblyQualifiedName.Length; ++i)
				{
					char c = AssemblyQualifiedName[i];
					if (c == '[')
					{
						++bcount;
						var b = new block() { iStart = i + 1, level = bcount, parentBlock = currentBlock };
						currentBlock.innerBlocks.Add(b);
						currentBlock = b;
					}
					else if (c == ']')
					{
						currentBlock.iEnd = i - 1;
						if (AssemblyQualifiedName[currentBlock.iStart] != '[')
						{
							currentBlock.parsedAssemblyQualifiedName = new ParsedAssemblyQualifiedName(AssemblyQualifiedName.Substring(currentBlock.iStart, i - currentBlock.iStart));
							if (bcount == 2)
								this.GenericParameters.Add(currentBlock.parsedAssemblyQualifiedName);
						}
						currentBlock = currentBlock.parentBlock;
						--bcount;
					}
					else if (bcount == 0 && c == ',')
					{
						index = i;
						break;
					}
				}
			}

			this.TypeName = AssemblyQualifiedName.Substring(0, index);

			this.CSharpStyleName = new Lazy<string>(
				() =>
				{
					return this.LanguageStyle("<", ">");
				});

			this.VBNetStyleName = new Lazy<string>(
				() =>
				{
					return this.LanguageStyle("(Of ", ")");
				});

			this.AssemblyDescriptionString = AssemblyQualifiedName.Substring(index + 2);

			{
				List<string> parts = AssemblyDescriptionString.Split(',')
																 .Select(x => x.Trim())
																 .ToList();
				this.Version = LookForPairThenRemove(parts, "Version");
				this.Culture = LookForPairThenRemove(parts, "Culture");
				this.internalKeyToken = LookForPairThenRemove(parts, "internalKeyToken");
				if (parts.Count > 0)
					this.ShortAssemblyName = parts[0];
			}

			this.AssemblyNameDescriptor = new Lazy<AssemblyName>(
				() => new System.Reflection.AssemblyName(this.AssemblyDescriptionString));

			this.FoundType = new Lazy<Type>(
				() => TypeFromAssemblyQualifiedName(AssemblyQualifiedName));
		}

		internal static Type TypeFromAssemblyQualifiedName(string AssemblyQualifiedName)
		{
			var searchedType = Type.GetType(AssemblyQualifiedName);
			if (searchedType != null)
				return searchedType;
			foreach (var assem in FrameworkTools.Framework.Assemblies.Value)
			{
				searchedType =
					assem.GetType(AssemblyQualifiedName);
				if (searchedType != null)
					return searchedType;
			}
			return null; // Not found.
		}


		internal string LanguageStyle(string prefix, string suffix)
		{
			if (this.GenericParameters.Count > 0)
			{
				StringBuilder sb = new StringBuilder(this.TypeName.Substring(0, this.TypeName.IndexOf('`')));
				sb.Append(prefix);
				bool pendingElement = false;
				foreach (var param in this.GenericParameters)
				{
					if (pendingElement)
						sb.Append(", ");
					sb.Append(param.LanguageStyle(prefix, suffix));
					pendingElement = true;
				}
				sb.Append(suffix);
				return sb.ToString();
			}
			else
				return this.TypeName;
		}

		class block
		{
			internal int iStart;
			internal int iEnd;
			internal int level;
			internal block parentBlock;
			internal List<block> innerBlocks = new List<block>();
			internal ParsedAssemblyQualifiedName parsedAssemblyQualifiedName;
		}

		static string LookForPairThenRemove(List<string> strings, string Name)
		{
			for (int istr = 0; istr < strings.Count; istr++)
			{
				string s = strings[istr];
				int i = s.IndexOf(Name);
				if (i == 0)
				{
					int i2 = s.IndexOf('=');
					if (i2 > 0)
					{
						string ret = s.Substring(i2 + 1);
						strings.RemoveAt(istr);
						return ret;
					}
				}
			}
			return null;
		}

#if DEBUG
		// Makes debugging easier.
		public override string ToString()
		{
			return this.CSharpStyleName.ToString();
		}
#endif
	}



}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under Microsoft Reciprocal License


Written By
Software Developer (Senior) independent
France France
Hi !

I made my first program on a Sinclair ZX-81.
Since that day, I have the virus of computers. Smile | :)

Here is my website:
https://chrisbertrand.net

And my blog:
https://chrisbertrandprogramer.wordpress.com/

Comments and Discussions