Avatar billede Droa Seniormester
15. april 2016 - 13:07 Der er 10 kommentarer

Lave et Interface for et Loadet Assembly

Hej Eksperter.

Jeg har prøvet og lave en form for Mod-loader til mit projekt så jeg let kan loade 3. part biblioteker uden og skulle re-compile min kode.

Lige pt har jeg prøvet med log4net, for og se hvad der kan lade sig gøre.


static void Main(string[] args)
        {
            Assembly assembly = Assembly.Load("log4net");
            Type BasicConfigurator = assembly.GetType("log4net.Config.BasicConfigurator");
            MethodInfo ConfigureMethod = BasicConfigurator.GetMethod("Configure", Type.EmptyTypes);

            ConfigureMethod.Invoke(null,new object[] { });

            Type LogManager = assembly.GetType("log4net.LogManager");

            MethodInfo GetLogger = LogManager.GetMethod("GetLogger", new[] { typeof(string) });
            object log = GetLogger.Invoke(null, new [] { "test" });

            MethodInfo Debug = log.GetType().GetMethod("Debug", new[] { typeof(string) });
            Debug.Invoke(log, new[] { "test" });

            Console.ReadKey();
        }


denne kode virker som forventet, dog ville jeg gerne have rammet den ind i et lidt bedre interface. så jeg tænkte om det kunne lade sig gøre og caste mit objekt til f.eks ILog, hvis jeg lavede en copi af det i mit projekt assembly?


using System;

namespace log4net
{
    public interface ILog
    {
        /* Test if a level is enabled for logging */
        bool IsDebugEnabled { get; }
        bool IsInfoEnabled { get; }
        bool IsWarnEnabled { get; }
        bool IsErrorEnabled { get; }
        bool IsFatalEnabled { get; }

        /* Log a message object */
        void Debug(object message);
        void Info(object message);
        void Warn(object message);
        void Error(object message);
        void Fatal(object message);

        /* Log a message object and exception */
        void Debug(object message, Exception t);
        void Info(object message, Exception t);
        void Warn(object message, Exception t);
        void Error(object message, Exception t);
        void Fatal(object message, Exception t);

        /* Log a message string using the System.String.Format syntax */
        void DebugFormat(string format, params object[] args);
        void InfoFormat(string format, params object[] args);
        void WarnFormat(string format, params object[] args);
        void ErrorFormat(string format, params object[] args);
        void FatalFormat(string format, params object[] args);

        /* Log a message string using the System.String.Format syntax */
        void DebugFormat(IFormatProvider provider, string format, params object[] args);
        void InfoFormat(IFormatProvider provider, string format, params object[] args);
        void WarnFormat(IFormatProvider provider, string format, params object[] args);
        void ErrorFormat(IFormatProvider provider, string format, params object[] args);
        void FatalFormat(IFormatProvider provider, string format, params object[] args);
    }
}


jeg har prøvet følgende, men det giver desværre fejl, så ville høre om det overhovedet var muligt, før jeg gravede dybere ned.


static void Main(string[] args)
        {
            Assembly assembly = Assembly.Load("log4net");
            Type BasicConfigurator = assembly.GetType("log4net.Config.BasicConfigurator");
            MethodInfo ConfigureMethod = BasicConfigurator.GetMethod("Configure", Type.EmptyTypes);

            ConfigureMethod.Invoke(null,new object[] { });

            Type LogManager = assembly.GetType("log4net.LogManager");

            MethodInfo GetLogger = LogManager.GetMethod("GetLogger", new[] { typeof(string) });
            object log = GetLogger.Invoke(null, new [] { "test" });

            MethodInfo Debug = log.GetType().GetMethod("Debug", new[] { typeof(string) });
            Debug.Invoke(log, new[] { "test" });

            ILog logger = (ILog)log;
            logger.Debug("test fra interface");

            Console.ReadKey();
        }
Avatar billede arne_v Ekspert
15. april 2016 - 14:26 #1
Lad mig gaette - du faar en cast fejl paa:

ILog logger = (ILog)log;

?
Avatar billede Droa Seniormester
15. april 2016 - 14:38 #2
Det er korrekt, jeg går ud fra det er fordi den ikke har samme signatur som i del filen :)
Avatar billede arne_v Ekspert
15. april 2016 - 15:03 #3
Nej. Det er fordi at alle type name er implicit prefixet med assembly.

{dinassembly}log4net.ILog og {log4netassembly}log4net.ILog er ikke samme type.
Avatar billede arne_v Ekspert
15. april 2016 - 15:05 #4
Foerst et hurtig note omkring logging.

http://netcommon.sourceforge.net/docs/2.1.0/reference/html/index.html loeser detr problem.

Men jeg formoder at du var interesseret i en mere generel loesning.
Avatar billede arne_v Ekspert
15. april 2016 - 15:09 #5
For dine egne plugins saa skal du nok have:

foobar.exe med din applikation
foobar.interface.dll med FooBar.IFooBar interface
arne.foobar.dll med Arne.FooBar.MyFooBar som implementerer FooBar.IFooBar
obama.foobar.dll med Potus.FooBar.TheFooBar som implementerer FooBar.IFooBar
etc.
Avatar billede arne_v Ekspert
15. april 2016 - 15:10 #6
Med given tredieparts DLL som ikke implementerer dit interface er du i problemer og bliver noedt til at create wrapper kode.
Avatar billede Droa Seniormester
15. april 2016 - 15:48 #7
Så der er ingen måde og caste f.eks igennem serializering eller lignene? Lige py prøver jeg bare og finde ud af hvordan et assembly fungerer og hvad man kan med det, log4net var bare et eksempel, men jeg regnede os med man vat nød til og lave en wrapper :) jeg skulle bare se om man kunne mere i dotnet, da man også er nød til det samme i Java.
Avatar billede Droa Seniormester
15. april 2016 - 22:48 #8
sad lige oppe og brugte lidt tid på denne kode, jeg har dog lavet så den kan cache adresserne, dog ved jeg ikke om det er nødvendigt, da jeg ikke helt ved hvor meget DotNet selv cacher i reflection.


using System;
using System.Reflection;

namespace LibHookTest
{
    public interface ILog
    {
        /* Test if a level is enabled for logging */
        bool IsDebugEnabled { get; }
        bool IsInfoEnabled { get; }
        bool IsWarnEnabled { get; }
        bool IsErrorEnabled { get; }
        bool IsFatalEnabled { get; }

        /* Log a message object */
        void Debug(object message);
        void Info(object message);
        void Warn(object message);
        void Error(object message);
        void Fatal(object message);

        /* Log a message object and exception */
        void Debug(object message, Exception t);
        void Info(object message, Exception t);
        void Warn(object message, Exception t);
        void Error(object message, Exception t);
        void Fatal(object message, Exception t);

        /* Log a message string using the System.String.Format syntax */
        void DebugFormat(string format, params object[] args);
        void InfoFormat(string format, params object[] args);
        void WarnFormat(string format, params object[] args);
        void ErrorFormat(string format, params object[] args);
        void FatalFormat(string format, params object[] args);

        /* Log a message string using the System.String.Format syntax */
        void DebugFormat(IFormatProvider provider, string format, params object[] args);
        void InfoFormat(IFormatProvider provider, string format, params object[] args);
        void WarnFormat(IFormatProvider provider, string format, params object[] args);
        void ErrorFormat(IFormatProvider provider, string format, params object[] args);
        void FatalFormat(IFormatProvider provider, string format, params object[] args);
    }


    public class Log : ILog
    {
        private object logger;

        private Type _thisType;
        private Type ThisType
        {
            get
            {
                if (_thisType == null) _thisType = logger.GetType();
                return _thisType;
            }
        }

        private PropertyInfo _isDebugEnabledProperty;
        private PropertyInfo _isErrorEnabledProperty;
        private PropertyInfo _isFatalEnabledProperty;
        private PropertyInfo _isInfoEnabledProperty;
        private PropertyInfo _isWarnEnabledProperty;

        private MethodInfo _DebugMethod1;
        private MethodInfo _DebugMethod2;
        private MethodInfo _DebugFormatMethod1;
        private MethodInfo _DebugFormatMethod2;
        private MethodInfo _ErrorMethod1;
        private MethodInfo _ErrorMethod2;
        private MethodInfo _ErrorFormatMethod1;
        private MethodInfo _ErrorFormatMethod2;
        private MethodInfo _FatalMethod1;
        private MethodInfo _FatalMethod2;
        private MethodInfo _FatalFormatMethod1;
        private MethodInfo _FatalFormatMethod2;
        private MethodInfo _InfoMethod1;
        private MethodInfo _InfoMethod2;
        private MethodInfo _InfoFormatMethod1;
        private MethodInfo _InfoFormatMethod2;
        private MethodInfo _WarnMethod1;
        private MethodInfo _WarnMethod2;
        private MethodInfo _WarnFormatMethod1;
        private MethodInfo _WarnFormatMethod2;

        public bool IsDebugEnabled
        {
            get
            {
                return ReflectSimplifierProperty<bool>(ref logger, ref _isDebugEnabledProperty, "IsDebugEnabled");
            }
        }

        public bool IsErrorEnabled
        {
            get
            {
                return ReflectSimplifierProperty<bool>(ref logger, ref _isErrorEnabledProperty, "IsErrorEnabled");
            }
        }

        public bool IsFatalEnabled
        {
            get
            {
                return ReflectSimplifierProperty<bool>(ref logger, ref _isFatalEnabledProperty, "IsFatalEnabled");
            }
        }

        public bool IsInfoEnabled
        {
            get
            {
                return ReflectSimplifierProperty<bool>(ref logger, ref _isInfoEnabledProperty, "IsInfoEnabled");
            }
        }

        public bool IsWarnEnabled
        {
            get
            {
                return ReflectSimplifierProperty<bool>(ref logger, ref _isWarnEnabledProperty, "IsWarnEnabled");
            }
        }

        public void Debug(object message)
        {
            ReflectSimplifiedMethod(ref logger, ref _DebugMethod1, "Debug",new [] { typeof(object) }, message);
        }

        public void Debug(object message, Exception t)
        {
            ReflectSimplifiedMethod(ref logger, ref _DebugMethod2, "Debug", new[] { typeof(object), typeof(Exception) }, message,t);
        }

        public void DebugFormat(string format, params object[] args)
        {
            ReflectSimplifiedMethod(ref logger, ref _DebugFormatMethod1, "DebugFormat", new[] { typeof(string), typeof(object[]) }, format, args);
        }

        public void DebugFormat(IFormatProvider provider, string format, params object[] args)
        {
            ReflectSimplifiedMethod(ref logger, ref _DebugFormatMethod2, "DebugFormat", new[] { typeof(IFormatProvider),typeof(string), typeof(object[]) }, provider,format, args);
        }

        public void Error(object message)
        {
            ReflectSimplifiedMethod(ref logger, ref _ErrorMethod1, "Error", new[] { typeof(object) }, message);
        }

        public void Error(object message, Exception t)
        {
            ReflectSimplifiedMethod(ref logger, ref _ErrorMethod2, "Error", new[] { typeof(object), typeof(Exception) }, message, t);
        }

        public void ErrorFormat(string format, params object[] args)
        {
            ReflectSimplifiedMethod(ref logger, ref _ErrorFormatMethod1, "ErrorFormat", new[] { typeof(string), typeof(object[]) },format,args);
        }

        public void ErrorFormat(IFormatProvider provider, string format, params object[] args)
        {
            ReflectSimplifiedMethod(ref logger, ref _ErrorFormatMethod2, "ErrorFormat", new[] { typeof(IFormatProvider),typeof(string), typeof(object[]) }, provider, format, args);
        }

        public void Fatal(object message)
        {
            ReflectSimplifiedMethod(ref logger, ref _FatalMethod1, "Fatal", new[] { typeof(object) }, message);
        }

        public void Fatal(object message, Exception t)
        {
            ReflectSimplifiedMethod(ref logger, ref _FatalMethod2, "Fatal", new[] { typeof(object),typeof(Exception) }, message,t);
        }

        public void FatalFormat(string format, params object[] args)
        {
            ReflectSimplifiedMethod(ref logger, ref _FatalFormatMethod1, "FatalFormat", new[] { typeof(string), typeof(object[]) }, format, args);
        }

        public void FatalFormat(IFormatProvider provider, string format, params object[] args)
        {
            ReflectSimplifiedMethod(ref logger, ref _FatalFormatMethod2, "FatalFormat", new[] { typeof(IFormatProvider), typeof(string), typeof(object[]) }, provider, format, args);
        }

        public void Info(object message)
        {
            ReflectSimplifiedMethod(ref logger, ref _InfoMethod1, "Info", new[] { typeof(object) }, message);
        }

        public void Info(object message, Exception t)
        {
            ReflectSimplifiedMethod(ref logger, ref _InfoMethod2, "Info", new[] { typeof(object), typeof(Exception) }, message, t);
        }

        public void InfoFormat(string format, params object[] args)
        {
            ReflectSimplifiedMethod(ref logger, ref _InfoFormatMethod1, "InfoFormat", new[] { typeof(string), typeof(object[]) }, format, args);
        }

        public void InfoFormat(IFormatProvider provider, string format, params object[] args)
        {
            ReflectSimplifiedMethod(ref logger, ref _InfoFormatMethod2, "InfoFormat", new[] { typeof(IFormatProvider), typeof(string), typeof(object[]) }, provider, format, args);
        }

        public void Warn(object message)
        {
            ReflectSimplifiedMethod(ref logger, ref _WarnMethod1, "Warn", new[] { typeof(object) }, message);
        }

        public void Warn(object message, Exception t)
        {
            ReflectSimplifiedMethod(ref logger, ref _WarnMethod2, "Warn", new[] { typeof(object), typeof(Exception) }, message, t);
        }

        public void WarnFormat(string format, params object[] args)
        {
            ReflectSimplifiedMethod(ref logger, ref _WarnFormatMethod1, "WarnFormat", new[] { typeof(string), typeof(object[]) }, format, args);
        }

        public void WarnFormat(IFormatProvider provider, string format, params object[] args)
        {
            ReflectSimplifiedMethod(ref logger, ref _WarnFormatMethod2, "WarnFormat", new[] { typeof(IFormatProvider), typeof(string), typeof(object[]) }, provider, format, args);
        }

        public Log(object logger)
        {
            this.logger = logger;

            if (ThisType.Namespace != "log4net.Core")
                throw new InvalidCastException("object is not from the correct framework");

            if (ThisType.Name != "LogImpl")
                throw new InvalidCastException("object is not a LogImpl Type");
        }

        static private T ReflectSimplifierProperty<T>(ref object obj, ref PropertyInfo cacheobj, string name)
        {
            if (cacheobj == null) cacheobj = obj.GetType().GetProperty(name, typeof(T));
            return (T)cacheobj.GetValue(obj);
        }

        static private void ReflectSimplifiedMethod(ref object obj, ref MethodInfo cacheobj, string name,Type[] types, params object[] args)
        {
            if (cacheobj == null) cacheobj = obj.GetType().GetMethod(name, types);
            cacheobj.Invoke(obj, args);
        }
    }
}



for og loade et gyldigt objekt, brugte jeg denne kode


using System;
using System.Reflection;

namespace LibHookTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly assembly = Assembly.Load("log4net");
            Type BasicConfigurator = assembly.GetType("log4net.Config.BasicConfigurator");
            MethodInfo ConfigureMethod = BasicConfigurator.GetMethod("Configure", Type.EmptyTypes);

            ConfigureMethod.Invoke(null,new object[] { });

            Type LogManager = assembly.GetType("log4net.LogManager");

            MethodInfo GetLogger = LogManager.GetMethod("GetLogger", new[] { typeof(string) });
            object log = GetLogger.Invoke(null, new [] { "test" });

            ILog logger = new Log(log);

            logger.Debug("Dette er en debug");
            logger.Debug("Dette er en debug med en exeption", new Exception("Fejl!"));
            logger.DebugFormat("Dette er en format debug: {0} {1}", logger.ToString(), logger.IsDebugEnabled);

            logger.Info("Dette er en Info");
            logger.Info("Dette er en Info med en exeption", new Exception("Fejl!"));
            logger.InfoFormat("Dette er en format Info: {0} {1}", logger.ToString(), logger.IsInfoEnabled);



            Console.ReadKey();
        }
    }
}
Avatar billede arne_v Ekspert
17. april 2016 - 16:26 #9
Jeg tror at det kan laves smartere.

Jeg vil proeve og kigge paa det senere.
Avatar billede arne_v Ekspert
18. april 2016 - 18:19 #10
Jeg har leget lidt med Castle.

Resultat:


using System;

using Castle.Core;
using Castle.DynamicProxy;

namespace ExternCodeA
{
    public interface ILogger
    {
        void LogA(string msg);   
    }
    public class Logger : ILogger
    {
        public void LogA(string msg)
        {
            Console.WriteLine("A: {0}", msg);
        }
    }
}

namespace ExternCodeB
{
    public interface ILogger
    {
        void LogB(string msg);   
    }
    public class Logger : ILogger
    {
        public void LogB(string msg)
        {
            Console.WriteLine("B: {0}", msg);
        }
    }
}


namespace MyCode
{
    public interface ICommonLogger
    {
        void Log(string msg);
    }
    public interface CommonLoggerPlus : ICommonLogger, ExternCodeA.ILogger, ExternCodeB.ILogger
    {
    }
    public interface IGlue
    {
        object Target { set; }
    }
    public class CommonLoggerGlueA : ICommonLogger, IGlue
    {
        private ExternCodeA.ILogger target;
        public object Target { set { target = (ExternCodeA.ILogger)value; } }
        public void Log(string msg)
        {
            target.LogA(msg);
        }
    }
    public class CommonLoggerGlueB : ICommonLogger, IGlue
    {
        private ExternCodeB.ILogger target;
        public object Target { set { target = (ExternCodeB.ILogger)value; } }
        public void Log(string msg)
        {
            target.LogB(msg);
        }
    }
    public static class CommonLoggerWrapper
    {
        private static ProxyGenerator gen = new ProxyGenerator();
        public static ICommonLogger Wrap<T>(T o, IGlue glue)
        {
            lock(gen)
            {
                ProxyGenerationOptions opts = new ProxyGenerationOptions();
                glue.Target = o;
                opts.AddMixinInstance(glue);
                return (ICommonLogger)gen.CreateClassProxyWithTarget(typeof(T), new Type[] { typeof(CommonLoggerPlus) }, o, opts);
            }
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            ICommonLogger loga = CommonLoggerWrapper.Wrap(new ExternCodeA.Logger(), new CommonLoggerGlueA());
            loga.Log("Test");
            ICommonLogger logb = CommonLoggerWrapper.Wrap(new ExternCodeB.Logger(), new CommonLoggerGlueB());
            logb.Log("Test");
            Console.ReadKey();
        }
    }
}
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester