//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
//
using System;
using System.Reflection;
using System.Xml.Serialization;

namespace ListTypes
{
	// Zdefiniowany przez użytkownika typ wartości.
	public struct MyStruct
	{
		public int a;
		public int b;
	}

	public enum Sample { Sample1, Sample2, Sample3};

	// Interfdjsy
	public interface IMyInterface
	{
		// Metoda zwraca tablicę
		string [] MyInterfaceMethod();
	}
	public interface IYourInterface
	{
		void YourInterfaceMethod(MyDelegate callback);
	}

	// Delegat
	public delegate void MyDelegate(string msg);

	// Klasa
	public class MyClass: IMyInterface, IYourInterface
	{
		// Pola
		private int myInt;
		private string myString;
		private Sample mySample;

		// Konstruktor
		public MyClass()
		{
			myInt = 0;
			myString = Assembly.GetCallingAssembly().FullName;
		}
		// Metoda
		public MyStruct MyMethod(int a, int b)
		{
			MyStruct ms = new MyStruct();
			ms.a = a;
			ms.b = b;
			return ms;
		}

		// Implementacje interfejsu
		public string [] MyInterfaceMethod()
		{
			string [] returnArray = new string[] {"Ten", "tekst", "zwrócono", "z", "MyMethod", "w", "IMyInterface"};
			return returnArray;
		}

		public void YourInterfaceMethod(MyDelegate yourCallback)
		{
			yourCallback("Hej ty!");
		}

		// Właściwość
		public int MyInt
		{
			get
			{
				return myInt;
			}
			set
			{
				myInt = value;
			}
		}

		// Inna właściwość
		public string MyString
		{
			get
			{
				return myString;
			}
		}

		// Jeszcze inna właściwość
		public Sample MyEnum
		{
			get
			{
				return mySample;
			}
			set
			{
				mySample = value;
			}
		}
	}
	class ListTypesMain
	{
		static void Main(string[] args)
		{
			// Załadowanie podzespołu przy użyciu jego nazwy pliku
			Assembly a = Assembly.GetExecutingAssembly();
			// Uzyskanie nazw typów z podzespołu
			Type [] types = a.GetTypes ();
			foreach (Type t in types)
			{
				MemberInfo[] mmi = t.GetMembers(); 
				// Uzyskanie i wyświetlenie metody DeclaringType. 
				Console.WriteLine("\n{0} elementów istnieje w {1}.", 
					mmi.Length, t.FullName);
				Console.WriteLine("{0} to {1}", t.FullName,
						(t.IsAbstract ? "abstrakt " : "") + 
						(t.IsArray ? "tablica " : "") + 
						(t.IsClass ? "klasa " : "") + 
						(t.IsContextful ? "kontekst " : "") +
						(t.IsInterface ? "interfejs " : "") +
						(t.IsPointer ? "wskaźnik " : "") +
						(t.IsPrimitive ? "prymityw " : "") +
						(t.IsPublic ? "publiczny " : "") +
						(t.IsSealed ? "zapieczętowany " : "") +
						(t.IsSerializable ? "podlega szeregowaniu " : "") +
						(t.IsValueType ? "wartość " : ""));
//				Console.WriteLine ("// Elementy");
//				PrintMembers (mmi);
//				// Najpierw są wyświetlane pola statyczne.
				FieldInfo [] fi;
//				fi = t.GetFields (BindingFlags.Static | 
//					              BindingFlags.NonPublic |
//					              BindingFlags.Public);
//				Console.WriteLine ("// Pola statyczne");
//				PrintMembers (fi);
//
//				PropertyInfo [] pi;
//				// Właściwości statyczne 
//				pi = t.GetProperties (BindingFlags.Static | 
//					                  BindingFlags.NonPublic |
//					                  BindingFlags.Public);
//				Console.WriteLine ("// Właściwości statyczne");
//				PrintMembers (pi);
//
//				// Zdarzenia statyczne 
//				EventInfo [] ei = t.GetEvents (BindingFlags.Static | 
//					                           BindingFlags.NonPublic |
//					                           BindingFlags.Public);
//				Console.WriteLine ("// Zdarzenia statyczne");
//				PrintMembers (ei);
//
//				// Metody statyczne 
//				MethodInfo [] mi = t.GetMethods (BindingFlags.Static | 
//					                             BindingFlags.NonPublic |
//					                             BindingFlags.Public);
//				Console.WriteLine ("// Metody statyczne");
//				PrintMembers (mi);
//
//				// Konstruktory 
//				ConstructorInfo [] ci = t.GetConstructors (BindingFlags.Instance | 
//					                                       BindingFlags.NonPublic |
//					                                       BindingFlags.Public);
//				Console.WriteLine ("// Konstruktory");
//				PrintMembers (ci);
//
				// Pola egzemplarzy 
				fi = t.GetFields (BindingFlags.Instance |
					              BindingFlags.NonPublic | 
					              BindingFlags.Public);
				Console.WriteLine ("// Pola egzemplarzy");
				PrintMembers (fi);
//
//				// Właściwości egzemplarzy 
//				pi = t.GetProperties (BindingFlags.Instance |
//					                  BindingFlags.NonPublic | 
//					                  BindingFlags.Public);
//				Console.WriteLine ("// Właściwości egzemplarzy");
//				PrintMembers (pi);
//
//				// Zdarzenia egzemplarzy 
//				ei = t.GetEvents (BindingFlags.Instance |
//					              BindingFlags.NonPublic | 
//					              BindingFlags.Public);
//				Console.WriteLine ("// Zdarzenia egzemplarzy ");
//				PrintMembers (ei);
//
//				// Metody egzemplarzy 
//				mi = t.GetMethods (BindingFlags.Instance |
//					               BindingFlags.NonPublic | 
//					               BindingFlags.Public);
//				Console.WriteLine Metody;
//				PrintMembers (mi);
			}

			// Teraz utworzenie egzemplarzy
			MyStruct [] s = new MyStruct [2];
			s[0].a = 1;
			s[0].b = 2;
			s[1].a = 3;
			s[1].b = 4;
		}
		public static void PrintMembers(MemberInfo [] ms) 
		{
			foreach (MemberInfo m in ms) 
			{
				if(m is ConstructorInfo)
				{
					Console.WriteLine ("{0}{1}{2}", "     ",  m, (((MethodBase)m).IsConstructor ? "constructor" : ""));
					Console.WriteLine ("{0} Element {1}", "     ", ((ConstructorInfo)m).DeclaringType);
					Console.WriteLine ("{0} Konwencja wywoływania {1}", "     ", ((ConstructorInfo)m).CallingConvention);
					ParameterInfo [] pi = ((ConstructorInfo)m).GetParameters();
					Console.WriteLine ("{0} Istnieje {1} parametrów.", "     ", pi.Length);
					foreach (ParameterInfo p in pi) 
					{
						Console.WriteLine ("{0}  {1} {2}", "     ", p.ParameterType, p.Name);
					}	
				}
				else if(m is MethodInfo)
				{
					Console.WriteLine ("{0}{1}", "     ", m);
					Console.WriteLine ("{0} Element {1}", "     ", ((MethodInfo)m).DeclaringType);
					Console.WriteLine ("{0} Konwencja wywoływania {1}", "     ", ((MethodInfo)m).CallingConvention);
					ParameterInfo [] pi = ((MethodInfo)m).GetParameters();
					Console.WriteLine ("{0} Istnieje {1} parametrów.", "     ", pi.Length);
					foreach (ParameterInfo p in pi) 
					{
						Console.WriteLine ("{0}  {1} {2}", "     ", p.ParameterType, p.Name);
					}	
					Console.WriteLine ("{0} zwraca {1}", "     ", ((MethodInfo)m).ReturnType);
				}
				else if(m is FieldInfo)
				{
					Console.WriteLine ("{0}{1}", "     ", m);
					// Uzyskanie wyliczonej wartości MethodAttribute
					FieldAttributes fieldAttributes = ((FieldInfo)m).Attributes;
					Console.Write ("{0} ", "     ");
					if((fieldAttributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Private)
						Console.Write("Prywatny ");
					if((fieldAttributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Public)
						Console.Write("Publiczny ");
					if((fieldAttributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Assembly)
						Console.Write("Podzespół ");
					if((fieldAttributes & FieldAttributes.FieldAccessMask) == FieldAttributes.FamANDAssem)
						Console.Write("FamANDAssem ");
					if((fieldAttributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Family)
						Console.Write("Rodzina ");
					if((fieldAttributes & FieldAttributes.FieldAccessMask) == FieldAttributes.FamORAssem)
						Console.Write("FamORAssem ");
					if((fieldAttributes & FieldAttributes.FieldAccessMask) == FieldAttributes.FamORAssem)
						Console.Write("FamORAssem ");
					if((fieldAttributes & FieldAttributes.HasDefault) != 0)
						Console.Write("HasDefault ");
					if((fieldAttributes & FieldAttributes.HasFieldMarshal) != 0)
						Console.Write("HasFieldMarshal ");
					if((fieldAttributes & FieldAttributes.HasFieldRVA) != 0)
						Console.Write("HasFieldRVA ");
					if((fieldAttributes & FieldAttributes.InitOnly) != 0)
						Console.Write("InitOnly ");
					if((fieldAttributes & FieldAttributes.Literal) != 0)
						Console.Write("Literał ");
					if((fieldAttributes & FieldAttributes.NotSerialized) != 0)
						Console.Write("NotSerialized ");
					if((fieldAttributes & FieldAttributes.PinvokeImpl) != 0)
						Console.Write("PinvokeImpl ");
					if((fieldAttributes & FieldAttributes.RTSpecialName) != 0)
						Console.Write("RTSpecialName ");
					if((fieldAttributes & FieldAttributes.SpecialName) != 0)
						Console.Write("SpecialName ");
					if((fieldAttributes & FieldAttributes.Static) != 0)
						Console.Write("Statyczny ");
					Console.WriteLine (((FieldInfo)m).FieldType);
					if(Attribute.GetCustomAttribute(m, typeof(Attribute)) != null)
						Console.WriteLine ("{0} {1}", "     ", Attribute.GetCustomAttribute(m, typeof(Attribute)));
					Console.WriteLine ("{0} Element {1}", "     ", ((FieldInfo)m).DeclaringType);
					Attribute attrib = Attribute.GetCustomAttribute(m, typeof(Attribute));
					XmlAttributeAttribute xmlAttrib = attrib as XmlAttributeAttribute;
					if(xmlAttrib != null)
					{
						Console.WriteLine("Nazwa: {0}", xmlAttrib.AttributeName);
						Console.WriteLine("Typ daty: {0}", xmlAttrib.DataType);
						Console.WriteLine("Formularz: {0}", xmlAttrib.Form);
						Console.WriteLine("Przestrzeń nazw: {0}", xmlAttrib.Namespace);
						Console.WriteLine("Typ: {0}", xmlAttrib.Type);
						Console.WriteLine("Identyfikator typu: {0}", xmlAttrib.TypeId);
					}
				}
				else if(m is PropertyInfo)
				{
					Console.WriteLine ("{0}{1}", "     ", m);
					Console.WriteLine ("{0} CanRead: {1}", "     ", ((PropertyInfo)m).CanRead);
					Console.WriteLine ("{0} CanWrite: {1}", "     ", ((PropertyInfo)m).CanWrite);
					Console.WriteLine ("{0} IsSpecialName: {1}", "     ", ((PropertyInfo)m).IsSpecialName);
					Console.WriteLine ("{0} Element: {1}", "     ", ((PropertyInfo)m).DeclaringType);
					Console.WriteLine ("{0} Typ elementu: {1}", "     ", ((PropertyInfo)m).MemberType);
					Console.WriteLine ("{0} Nazwa: {1}", "     ", ((PropertyInfo)m).Name);
					Console.WriteLine ("{0} Typ właściwości: {1}", "     ", ((PropertyInfo)m).PropertyType);
					Console.WriteLine ("{0} Typ refleksji {1}", "     ", ((PropertyInfo)m).ReflectedType);
					if(((PropertyInfo)m).GetGetMethod() != null)
					{
						Console.WriteLine ("{0} Uzyskanie: {1}", "     ", ((PropertyInfo)m).GetGetMethod());
						Console.WriteLine ("{0}      Typ zwrotny {1}", "     ", ((PropertyInfo)m).GetGetMethod().ReturnType);
					}
					if(((PropertyInfo)m).GetSetMethod() != null)
					{
						Console.WriteLine ("{0} Ustawienie: {1}", "     ", ((PropertyInfo)m).GetSetMethod());
						Console.WriteLine ("{0}      Typ zwrotny {1}", "     ", ((PropertyInfo)m).GetSetMethod().ReturnType);
					}
				}
				else
				{
					Console.WriteLine ("{0}{1}", "     Typ: ", m);
				}
			}
			Console.WriteLine();
		}
	}
}
