Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Typkonvertierungen mit TypeConverter (Extension)
dr4g0n76
myCSharp.de - Experte

Avatar #avatar-1768.jpg


Dabei seit:
Beiträge: 3047
Herkunft: Deutschland

Themenstarter:

Typkonvertierungen mit TypeConverter (Extension)

beantworten | zitieren | melden

Mit untenstehender Klasse ist folgendes möglich:
(1. Version)

Arrays, Listen bzw. IEnumerables können konvertiert werden.
Von einem Typ in den anderen.
Selbst wenn die Klasse keinen entsprechenden AddRange-Befehl oder Konstruktor hat, ist das auch möglich.

Ich muss also nicht mehr schreiben:



Wenn z.B.


    //Complex conversions
            char[] a = new char[] { 'm', 'u', 'l', 't', 'u', 'm', 'e', 's', 'c' };
            byte[] b = new byte[] { 65, 66, 66, 65, 65, 66, 65, 66 };

            int[] resultIntArrayFromCharArray = (int[])typeof(int[]).Cast(a);
            int[] resultIntArrayFromByteArray = (int[])typeof(int[]).Cast(b);
            char[] resultCharArray = (char[])typeof(char[]).Cast(b);
            byte[] resultByteArray = (byte[])typeof(byte[]).Cast(a);
            //--------------------------------------------------------------------------
            //Convert from IEnumerable<Guid> to ObservableCollection<Guid>
            IEnumerable<Guid> guids = new Guid[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
            ObservableCollection<Guid> observableCollectionGuid = (ObservableCollection<Guid>)typeof(ObservableCollection<Guid>).Cast(guids);

            //Convert from ObservableCollection<Guid> to IEnumerable<Guid>
            ObservableCollection<Guid> observableCollectionGuid2 = new ObservableCollection<Guid>(new Guid[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() });
            IEnumerable<Guid> guids2 = (IEnumerable<Guid>)typeof(IEnumerable<Guid>).Cast(observableCollectionGuid2);

            //--------------------------------------------------------------------------
            //Simple conversion
            int intValue = 339;
            double? doubleValueCastedNullable = (double?)typeof(double?).Cast(intValue);

            intValue = 90943;
            double doubleValueCasted = (double)typeof(double).Cast(intValue); 

            double doubleValue = 7.0d;
            float floatValueCasted = (float)typeof(float).Cast(doubleValue);

            float floatValue = 3.09f;
            decimal decimalValueCasted = (decimal)typeof(decimal).Cast(floatValue);

            //--------------------------------------------------------------------------
            try
            {
                //at the moment an invalid cast exception is expected, when casting an array to one element
                string[] textValues = new string[] { "Hallo", "Hello", "Hola", "olá", "buna", "jak", "dag" };
                string sText = (string)typeof(string).Cast(textValues);
            }
            catch (InvalidCastException ex)
            {
                //so now we get an invalid cast
            }
            catch (Exception ex)
            {
            }

            //This will be casted, but at the moment makes no sense at all.
            //So one shouldn't do this.
            try
            {
                byte[] intValues = new byte[] { 7, 3, 9, 8, 5, 9 };
                int value = (int)typeof(int).Cast(intValue);
            }
            catch (InvalidCastException ex)
            {
            }
            catch (Exception ex)
            {
            }

            //--------------------------------------------------------------------------
            //This is possible: cast a single value to a list
            string textValue = "Hallo";
            List<string> sText2 = (List<string>)typeof(List<string>).Cast(textValue);

            //This is possible: cast a single value to a list
            Guid singleGuid = Guid.NewGuid();
            List<Guid> guidsOfSingleGuid = (List<Guid>)typeof(List<Guid>).Cast(singleGuid);

            intValue = 737;
            List<int> intsOfSingleInt = (List<int>)typeof(List<int>).Cast(intValue);

            bool trueValue = true;
            List<bool> boolsOfSingleBool = (List<bool>)typeof(List<bool>).Cast(trueValue);

         
            //--------------------------------------------------------------------------
            //This is also possible: Convert object to string: internally call object.ToString()
            intValue = 3457;
            string intValueCastedToString = (string)typeof(string).Cast(intValue);


using System;
using System.Runtime.CompilerServices;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using DynamicFramework.Iterators;

namespace DynamicFramework.TypeCast
{
    /// <summary>
    /// Use this class to do any type casts that would consume programming and code in one line.
    /// even casting like this is allowed:
    /// 
    /// 
    /// 
    /// </summary>
    public static class TypeCast
    {
        // This is the method exposing the rest of the functionality
        /// <summary>
        /// Casts the specified type.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="obj">The object.</param>
        /// <returns></returns>
        public static object Cast(this Type type, object obj)
        {
            return GetConverter(type, obj)(obj);
        }

        /// <summary>
        /// Converters contains the cached converters, 
        /// so using once it might be slow, the second time a cached converter
        /// will be used if possible.
        /// </summary>
        private static readonly IDictionary<PairOfTypes, Func<object, object>> converters =
            new Dictionary<PairOfTypes, Func<object, object>>();
        
        private static readonly ParameterExpression convParameter =
            Expression.Parameter(typeof(object), "val");

        /// <summary>
        /// Gets the converter.
        /// </summary>
        /// <param name="targetType">Type of the target.</param>
        /// <param name="val">The value.</param>
        /// <returns></returns>
        /// This is the method with the "guts" of the implementation
        [MethodImpl(MethodImplOptions.Synchronized)]
        private static Func<object, object> GetConverter(Type targetType, object val)
        {
            var fromType = val != null ? val.GetType() : typeof(object);
            var key = new PairOfTypes(fromType, targetType);
            Func<object, object> res;
            if (converters.TryGetValue(key, out res))
            {
                return res;
            }

            bool bConverted = true;
            try
            {
                res = (Func<object, object>)Expression.Lambda(
                    Expression.Convert(
                        Expression.Convert(
                            Expression.Convert(
                                convParameter
                            , fromType
                            )
                        , targetType
                        )
                    , typeof(object)
                    )
                , convParameter
                ).Compile();
                converters.Add(key, res);
            }
            catch (InvalidOperationException ex)
            {
                bConverted = false;
            }
            catch (Exception ex)
            {
                bConverted = false;
            }
            if (!bConverted)
            {
                IList listTargetType = null;
                IEnumerable listSourceType = val as IEnumerable;
                if (listSourceType != null)
                {
                    if (targetType.IsArray)
                    {

//TODO: for silverlight, what to do if there is an interface...
#if !SILVERLIGHT
                        if (listSourceType.GetType().GetInterface(typeof(IList).Name) != null)
                        {
                            IList list = (IList)listSourceType;
                            int count = list.Count;
                            listTargetType = (IList)Activator.CreateInstance(targetType, count);

                            int i = 0;
                            foreach (object oElement in Iter.All(listSourceType))
                            {
                                //unbox if needed, don't know yet, how to do by reflection
                                if (oElement.GetType() == typeof(char) && GetBaseTypeOfGenericIEnumerableType(listTargetType.GetType()) == typeof(byte))
                                {
                                    listTargetType[i++] = (byte)(char)oElement;
                                }
                                else
                                {
                                    listTargetType[i++] = oElement;
                                }
                            }
                        }
#endif
                    }
                    else
                    {
                        if (targetType == typeof(string))
                        {
                            throw new InvalidCastException(); //this is invalid, because one doesn't know how to convert an array into one element here.
                        }
                        listTargetType = (IList)Activator.CreateInstance(targetType);

                        if (val.GetType() == typeof(string))
                        {
                            listTargetType.Add(val);
                        }
                        else
                        {
                            foreach (object oElement in listSourceType)
                            {
                                listTargetType.Add(oElement);
                            }
                        }
                    }
                    //still null? consider case converting ONE element on source into list of elements in target
                }
                else
                {
                    if (targetType.FullName.Contains(val.GetType().FullName))
                    {
                        Type baseType = GetBaseTypeOfGenericIEnumerableType(targetType);
                        listTargetType = (IList)Activator.CreateInstance(targetType);
                        listTargetType.Add(val);
                    }
                }
                if (targetType == typeof(string) && listTargetType == null)
                {
                    res = (Func<object, object>)(x => val.ToString());
                    converters.Add(key, res);
                    return res;
                }
                else if (targetType.IsGenericType 
                    && listTargetType == null
                    && targetType.Name.Contains("List`1"))
                {
                    listTargetType = (IList)Activator.CreateInstance(targetType);
                    listTargetType.Add(val);
                }
                res = (Func<object, object>)(x => listTargetType); //this will get us what we want
                //converters.Add(key, res);
            }
            return res;
        }

        //TODO: avoid this method, if possible, but for the moment it's perfect.
        /// <summary>
        /// Found no other way to do this yet.
        /// </summary>
        /// <param name="targetType"></param>
        /// <returns></returns>
        public static Type GetBaseTypeOfGenericIEnumerableType(Type targetType)
        {
            string[] elements = System.Text.RegularExpressions.Regex.Split(targetType.FullName, @",|\[\[");
            if (elements.Length > 1)
            {
                return Type.GetType(elements[1]);
            }
            else
            {
                return Type.GetType(elements[0].TrimEnd(']').TrimEnd('['));
            }
        }
#if !FRAMEWORK35
        /// <summary>
        /// Converts the specified original.
        /// </summary>
        /// <param name="original">The original.</param>
        /// <returns></returns>
        public static ObservableCollection<object> Convert(IEnumerable original)
        {
            return new ObservableCollection<object>(original.Cast<object>());
        }

        /// <summary>
        /// Converts the specified original.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="original">The original.</param>
        /// <returns></returns>
        public static ObservableCollection<T> Convert<T>(IEnumerable<T> original)
        {
            return new ObservableCollection<T>(original);
        }

        /// <summary>
        /// Converts the specified original.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="original">The original.</param>
        /// <returns></returns>
        public static ObservableCollection<T> Convert<T>(IEnumerable original)
        {
            return new ObservableCollection<T>(original.Cast<T>());
        }
#endif
        
        /// <summary>
        /// Find out how to really unbox!!!
        /// </summary>
        /// <param name="oElement"></param>
        /// <param name="sourceType"></param>
        /// <param name="destinationType"></param>
        /// <returns></returns>
        private static object Unbox(object oElement, Type sourceType, Type destinationType)
        {
            if (sourceType == typeof(char) && destinationType == typeof(byte))
            {
                oElement = (byte)(char)oElement;
            }
            return oElement;
        }

        // This class provides Equals and GetHashCode
        // for a pair of System.Type objects.
        private class PairOfTypes
        {
            private readonly Type first;
            private readonly Type second;
            public PairOfTypes(Type first, Type second)
            {
                this.first = first;
                this.second = second;
            }
            public override int GetHashCode()
            {
                return 31 * first.GetHashCode() + second.GetHashCode();
            }
            public override bool Equals(object obj)
            {
                if (obj == this)
                {
                    return true;
                }
                var other = obj as PairOfTypes;
                if (other == null)
                {
                    return false;
                }
                return first.Equals(other.first)
                    && second.Equals(other.second);
            }
        }
    }
}
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von dr4g0n76 am .
Attachments
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
private Nachricht | Beiträge des Benutzers
dr4g0n76
myCSharp.de - Experte

Avatar #avatar-1768.jpg


Dabei seit:
Beiträge: 3047
Herkunft: Deutschland

Themenstarter:

beantworten | zitieren | melden

Anmerkung:

Gerade erst bemerkt.
Die Klasse benutzt einen Namespace der sich DynamicFramework.Iterators nennt.

Das ist nichts anderes als die komplett unveränderte Lösung für Iteratoren von Herbivore auf:

Hilfreiche Iteratoren / Improving Foreach

EDIT: Damit lässt sich die Klasse benutzen und fehlerfrei kompilieren.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von dr4g0n76 am .
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
private Nachricht | Beiträge des Benutzers
dr4g0n76
myCSharp.de - Experte

Avatar #avatar-1768.jpg


Dabei seit:
Beiträge: 3047
Herkunft: Deutschland

Themenstarter:

beantworten | zitieren | melden

Ich habe ein Beispiel-Projekt angehängt im obersten Post, dann kann jeder ausprobieren und muss nicht erst beide Klassen in ein Projekt kopieren.

Auf jede der Funktionen die über die entsprechenden Buttons der Form gesetzt sind, sind Breakpoints gesetzt, so dass sich jeder in Ruhe anschauen kann was passiert.

Ich editiere den oberen Beitrag nochmals, so dass einige Dinge etwas klarer werden sollten.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von dr4g0n76 am .
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
private Nachricht | Beiträge des Benutzers
dr4g0n76
myCSharp.de - Experte

Avatar #avatar-1768.jpg


Dabei seit:
Beiträge: 3047
Herkunft: Deutschland

Themenstarter:

beantworten | zitieren | melden

Hat irgendjemand zufällig eine Idee, wie man bei

List<Guid> guidsOfSingleGuid = (List<Guid>)typeof(List<Guid>).Cast(singleGuid);

um das

(List<Guid>)typeof(List<Guid>).Cast(singleGuid);

herumkommt?

Also dass man statt (List<Guid>)typeof(List<Guid>).Cast(singleGuid);
quasi was ganz kurzes schreiben könnte, was eben näher an:

List<Guid> guidsOfSingleGuid = singleGuid.CastTo(List<Guid>);
ist?
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5960
Herkunft: Leipzig

beantworten | zitieren | melden

Hi dr4g0n76,

meinst du soetwas:


public static IEnumerable<T> ToEnumerable<T>(this T item)
{
  yield return item;
}


List<Guid> guidsOfSingleGuid = singleGuid.ToEnumerable().ToList();
Weeks of programming can save you hours of planning
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 3978

beantworten | zitieren | melden

Hallo dr4g0n76,

wenn dann wohl


List<Guid> guidsOfSingleGuid = singleGuid.CastTo<List<Guid>>();
denn sonst müßtest du ja


List<Guid> guidsOfSingleGuid = singleGuid.CastTo(typeof(List<Guid>));
schreiben.

Und das geht dann per


public static T CastTo(this Guid guid)
{
    return (T)typeof(T).Cast(guid);
}
Wenn T aber immer List<Guid> ist, kannst du es natürlich vereinfachen (spezialisieren):


public static List<Guid> CastTo(this Guid guid)
{
    return (List<Guid>)typeof(List<Guid>).Cast(guid);
}
(Extension-Methoden müssen dann natürlich in eine eigene statische Klasse z.B. GuidExtensions)
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Th69 am .
private Nachricht | Beiträge des Benutzers