Laden...
K
Kani myCSharp.de - Member
Softwareprojektant und -Entwickler Potsdam Dabei seit 04.05.2006 174 Beiträge
Benutzerbeschreibung

Forenbeiträge von Kani Ingesamt 174 Beiträge

29.01.2013 - 09:58 Uhr

Hallo console,

Google liefert als erstes Ergebnis einen Thread, wo von einem Bug in MVC4 die rede ist (ob der jemals behoben wurde: keine Ahnung). Am Ende wird jedoch vorgeschlagen die Sonderzeichen mittels \uxxxx zu escapen...

Evtl. hilft das.

Gruß,
Kani

31.08.2010 - 21:27 Uhr

Also bei mir hat's geklappt.

Siehe Bild im Anhang.

31.08.2010 - 21:19 Uhr

Hallo pogo,

vielleicht geht diese Überladung:


[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, StringBuilder lParam);

Gefunden auf P/Invoke.net.

Grüße,
Kani

14.04.2010 - 21:48 Uhr

Hallo Peter,

vielen Dank für die Antwort.

Die Interfaces wurden deshalb gesplittet, da sie auch einzelne Verantwortlichkeiten darstellen (benachrichtigen und ausführen).

Ein Interface drüber zu setzen stellt nicht das Problem da:


interface IMyLogic : IVeryIntelligentLogic, INotificator
{
}

Dann habe ich aber immer noch das Problem, dass ich wo anders nur INotificator erwarte.... und ich kann nicht ein und die selbe Instanz von

MyLogic sowohl auf IMyLogic als auch auf INotificator als auch auf IVeryIntelligentLogic registrieren.

Und wenn ich INotificator als Komponente reinreichen würde, könnte ich aus MyLogic heraus nicht die Events auslösen....

Was wäre mit folgender Lösung:


using System;
using LightCore;

interface INotificator
{
    event EventHandler SomethingHappened;
}

interface IVeryIntelligentLogic
{
    void DoSomething();
}

// Komponentenadapter
public interface IComponentAdapter<TTarget>
{
    TTarget Component { get; }
}

public abstract class ComponentAdapterBase<TTarget> : IComponentAdapter<TTarget>
{
    private readonly Func<TTarget> _adapterFunction;

    protected ComponentAdapterBase(Func<TTarget> adapterFunction)
    {
        _adapterFunction = adapterFunction;
    }

    public TTarget Component { get { return _adapterFunction(); } }
}

public class ComponentAdapter<TSource, TTarget> : ComponentAdapterBase<TTarget>
    where TSource : IComponentAdapter<TTarget>
{
    public ComponentAdapter(TSource source)
        : base(() => source.Component)
    {
    }
}

interface IMyLogic : IComponentAdapter<IVeryIntelligentLogic>, IComponentAdapter<INotificator>
{
}

interface IExecuter
{
    void Execute();
}

interface IWatcher
{
}

class MyLogic : IMyLogic, IVeryIntelligentLogic, INotificator
{
    public void DoSomething()
    {
        OnSomethingHappened(EventArgs.Empty);
    }

    public event EventHandler SomethingHappened;

    protected virtual void OnSomethingHappened(EventArgs e)
    {
        var handler = SomethingHappened;
        if(handler != null)
            handler(this, e);
    }

    #region Implementation of IComponentAdapter<IVeryIntelligentLogic>

    IVeryIntelligentLogic IComponentAdapter<IVeryIntelligentLogic>.Component { get { return this; } }

    #endregion

    #region Implementation of IComponentAdapter<INotificator>

    INotificator IComponentAdapter<INotificator>.Component { get { return this; } }

    #endregion
}

class MyExecuter : IExecuter
{
    private readonly IVeryIntelligentLogic _logic;

    public MyExecuter(IComponentAdapter<IVeryIntelligentLogic> logic)
    {
        _logic = logic.Component;
    }

    public void Execute()
    {
       // ... do some things....
       // ...

       // .... then do soemthing
       _logic.DoSomething();

       // ... and do many other things...
       // ...
    }
}

class MyWatcher : IWatcher
{
    public MyWatcher(IComponentAdapter<INotificator> notificator)
    {
        notificator.Component.SomethingHappened += (sender, e) => Console.WriteLine("Something happened!");
    }
}

class Program
{
    public static void Main()
    {
        var containerBuilder = new ContainerBuilder();

        containerBuilder.DefaultControlledBy<TSingletonLifecycle>();

        containerBuilder.Register<IMyLogic, MyLogic>();
        containerBuilder.Register<IComponentAdapter<IVeryIntelligentLogic>, ComponentAdapter<IVeryIntelligentLogic>>();
        containerBuilder.Register<IComponentAdapter<INotificator>, ComponentAdapter<INotificator>>();
        // geht das auch mit containerBuilder.Register<IComponentAdapter<>, ComponentAdapter<>>() ?

        containerBuilder.Register<IExecuter, MyExecuter>();
        containerBuilder.Register<IWatcher, MyWatcher>();

        var container = containerBuilder.Build();

        var executer = container.Resolve<IExecuter>();

        executer.Execute(); // should produce Console.WriteLine("Something happened!");
    }
}

Das wäre dann (über IComponentAdapter + ComponentAdapter) allgemein gültiger..... und es würde für meine Zwecke funktionieren..... und....... xml wäre möglich, oder?

Grüße,
Kani

P.S.: Bei all den Fragen hatte ich ganz vergessen zu erwähnen, dass ich LightCore wirklich gut gelungen finde (vor allem bei der beachtlich kleinen Größe, und dem konsequenten Einsatz von CCD).... respect 😉!

13.04.2010 - 12:43 Uhr

Das gleiche habe ich auch gelesen... ich glaube es war hier: MSDN Blog

Grüße Kani

13.04.2010 - 11:16 Uhr

@Jake:
Wenn ihr damals VS2008Pro + MSDN Pro genommen habt, dann bekommt ihr meines Wissens nach jetzt auch nur VS 2010 Pro + MSDN Pro...
Wir haben damals VS2008Pro + MSDN Premium genommen und gestern wurde VS2010 Premium im MSDN Portal freigeschaltet....

Grüße,
Kani

12.04.2010 - 22:12 Uhr

Hallo Kanti,

in den von dir geposteten Informationen scheint erstmal kein Fehler drin zu sein......
Wäre es möglich, dass du deine Projektmappe mal gezippt postest?
Zumindest die wichtigsten Teile...

Grüße,
Kani

12.04.2010 - 18:25 Uhr

Ok.... ich hab dann mal ein viel kürzeres und auf jedem Rechner ausführbares Beispiel verfasst.
Es geht nun darum, dass es zwei interfaces gibt:
Das eine deklariert eine Methode, das andere ein Event.
Beide interfaces werden nun von einer Klasse implementiert und diese feuert innerhalb der Methode,
die am ersten Interface deklariert wurde das event, welches an dem zweiten interface deklariert wurde.
An einigen Stellen (im Beispiel eine) wird nun das erste interface als Abhängigkeit im ctor erwartet,
an anderen Stellen das andere interface.
Übergeben werden muss natürlich überall die selbe Instanz......:


using System;
using LightCore;

interface INotificator
{
    event EventHandler SomethingHappened;
}

interface IVeryIntelligentLogic
{
    void DoSomething();
}

interface IExecuter
{
    void Execute();
}

interface IWatcher
{
}

class MyLogic : IVeryIntelligentLogic, INotificator
{
    public void DoSomething()
    {
        OnSomethingHappened(EventArgs.Empty);
    }

    public event EventHandler SomethingHappened;

    protected virtual void OnSomethingHappened(EventArgs e)
    {
        var handler = SomethingHappened;
        if(handler != null)
            handler(this, e);
    }
}

class MyExecuter : IExecuter
{
    private readonly IVeryIntelligentLogic _logic;

    public MyExecuter(IVeryIntelligentLogic logic)
    {
        _logic = logic;
    }

    public void Execute()
    {
       // ... do some things....
       // ...

       // .... then do soemthing
       _logic.DoSomething();

       // ... and do many other things...
       // ...
    }
}

class MyWatcher : IWatcher
{
    public MyWatcher(INotificator notificator)
    {
        notificator.SomethingHappened += (sender, e) => Console.WriteLine("Something happened!");
    }
}

class Program
{
    public static void Main()
    {
        var containerBuilder = new ContainerBuilder()
        
        containerBuilder.Register<MyLogic>().ControlledBy<SingletonLifecycle>();
        containerBuilder.Register<IVeryIntelligentLogic>(c => c.Resolve<MyLogic>()); // same instance
        containerBuilder.Register<INotificator>(c => c.Resolve<MyLogic>()); // same instance

        containerBuilder.Register<IExecuter, MyExecuter>();
        containerBuilder.Register<IWatcher, MyWatcher>();

        var container = containerBuilder.Build();

        var executer = container.Resolve<IExecuter>();

        executer.Execute(); // should produce Console.WriteLine("Something happened!");
    }
}

Das ist per Code-Config nun implementierbar, mit Xml-Config eben nicht.

Ist das nun vom Definieren der interfaces her schlechtes Design?
Wenn ja, wie würde man es richtig bzw. besser machen?

Grüße,
Kani

12.04.2010 - 12:54 Uhr

Hat mein (zugegeben etwas langer und vielleicht auch unverständlicher) Post jetzt abgeschreckt? 😉
Wenn ja, klärt mich bitte auf, dann würde ich versuchen, das nochmal etwas abgespeckter aufzuzeigen oder aber doch wieder ein anderes Beispiel zu konstruieren....

Grüße,
Kani

12.04.2010 - 12:23 Uhr

Hi Leute,

ich habe auch wie gespannt vor dem Counter gesessen.... und dann bei 0..... nüscht!
Hab dann mal bissl probiert und herausgefunden, dass der Counter scheinbar auf Betriebssystemuhrzeit läuft.... (stellt sie mal auf redmondzeit ein, dort ists gerade ca. 03:25).
Offizieller Release scheint irgendwo gegen 08:30 Redmondzeit zu sein, also bei uns gegen ca. 17:30....

Also heißsts nun aushalten....

Grüße,
Kani

10.04.2010 - 14:57 Uhr

Hallo Peter,

nun ja, wofür das gut sein soll, ist aus meinem fiktiven Beispiel natürlich kaum zu erkennen....
Deshalb poste ich jetzt doch mal den Code meines Kollegen um das Problem besser aufzuzeigen.
In dem Projekt geht es darum, den CPLEX-Kern von IBM/ILOG anzusprechen und entsprechende Mathematische Modelle von diesem optimieren zu lassen und während dieses Vorgangs auch Informationen abzufangen und ggf. anzuzeigen.

IModelSolvingBetterSolutionNotification: Definiert ein Event zur Benachrichtigung darüber, dass eine bessere Lösung gefunden wurde.


using System;

namespace Moveo.Profahr.Optimization.Infrastructure
{
    /// <summary>
    /// Interface für Klassen, die einen EventHandler für die Verlaufsmeldungen der Optimierung umsetzen.
    /// </summary>
    public interface IModelSolvingBetterSolutionNotification
    {
        /// <summary>
        /// EventHandler für die Verlaufsmeldung der Optimierung, mit dem Argument <see cref="BetterSolutionEventArgs"/>
        /// </summary>
        event EventHandler<BetterSolutionEventArgs> BetterSolutionFound;
    }
}

IModelSolvingTracker: Definiert eine Methode, die ein Model entgegen nimmt.


namespace Moveo.Profahr.Optimization.BusinessLogic.Impl
{
    /// <summary>
    /// Interface für Klassen, die den Lösungsverlauf eines gegebenen Models verfolgen können
    /// </summary>
    /// <remarks><see cref="ModelSolverCallback"/> ist ein IModelSolvingTracker</remarks>
    internal interface IModelSolvingTracker
    {
        /// <summary>
        /// Nimmt ein Modell entgegen, dessen Lösungsweg verfolgt werden soll
        /// </summary>
        /// <param name="model"><see cref="Model"/></param>
        void PassModel(Model model);
    }
}

ModelSolverCallback: Ist eine Klasse, die von der Klasse ILOG.CPLEX.Cplex.MIPInfoCallback erbt um später als Callbackmechanismus an den CPLEX-Kern übergeben werden zu können.
Von IBM/ILOG-CPLEX wird immer die Main-Methode aufgerufen, wenn sich der Lösungsfortschritt geändert hat.
Des weiteren werden die beiden Schnittstellen IModelSolvingTracker, sodass ein Model übergeben werden kann und IModelSolvingBetterSolutionNotification, für die Benachrichtigung des Lösungsfortschritts, implementiert.


using System;
using System.ComponentModel;
using ILOG.Concert;
using Moveo.Profahr.Optimization.BusinessLogic.Contract;
using Moveo.Profahr.Optimization.Infrastructure;

namespace Moveo.Profahr.Optimization.BusinessLogic.Impl
{
    internal sealed class ModelSolverCallback : ILOG.CPLEX.Cplex.MIPInfoCallback, IModelSolvingBetterSolutionNotification, IModelSolvingTracker
    {
        /// <summary>
        /// Da der SynchronisationContext nicht konkret anprogrammiert werden soll,
        /// wird über das AsyncPattern2 und den AsyncOperationManager gearbeitet.
        /// Dieser bietet den Vorteil automatisch den SynchronisationContext bereitzustellen
        /// in dem der Aufruf stattfindet (GUI, System.Thread, etc.)
        /// Hier handelt es sich um den Kontext des Threads in dem IModelSolver.Solve ausgeführt wird.
        /// Das kann entweder dirket der Thread der BL sein z.b. beim <see cref="SequentialOptimizationManager"/> oder
        /// ein aus der BL neu gestarteter Thread z.B. beim <see cref="ThreadOptimizationManager"/>
        /// </summary>
        private readonly AsyncOperation _asyncOperation;

        /// <summary>
        /// Das Modell desen Lösungsweg verfolgt werden soll
        /// </summary>
        private Model _model;


        public ModelSolverCallback()
        {
            _asyncOperation = AsyncOperationManager.CreateOperation(null);
        }


        /// <summary>
        /// Eigentlicher Callback, der laut Basisklasse ILOG.CPLEX.Cplex.Callback zu überschreiben ist
        /// </summary>
        /// <exception cref="InvalidOperationException">Wenn das zu verfolgende OplModel nicht initialisiert wurde</exception>
        /// <exception cref="IloException">Wenn die vorausgesetzen Modellelemente nicht definiert sind</exception>
        protected override void Main()
        {
            // Vorbedingung es muß ein gültiges Modell mit zulässigen Elementen vorhanden sein
            if ((_model == null) || (_model.OplModel == null))
            {
                //InvalidOperation
                throw new InvalidOperationException("_model und _model.OplModel müssen initialisiert werden!");
            }

            //ToDo algorithm und lowerBoundStatus Zusammenhänge näher analysieren
            var solverName = _model.SolverName;
            var currentStep = _model.CurrentStep;
            var maximalSteps = _model.MaximalSteps;
            /*
            var algorithm = _oplModel.GetElement(Model.VariableAlgorithm).AsInt();
            var lowerBoundGlobal = _oplModel.GetElement(Model.VariableLowerBoundGlobal).AsInt();
            var lowerBoundLocal = _oplModel.GetElement(Model.VariableLowerBoundLocal).AsInt();
            var lowerBoundStatus = _oplModel.GetElement(Model.VariableLowerBoundStatus).AsInt();
            */

            // Cplex Informationen auslesen
            var bestObjValue = GetBestObjValue();
            
            double? incumbmentValue = null;
            if (HasIncumbent())
            {
                incumbmentValue = GetIncumbentObjValue();
            }

            System.Diagnostics.Debug.WriteLine(string.Format("{0} bestObjValue={1} / actObjValue={2}", solverName, bestObjValue, incumbmentValue));
            _asyncOperation.Post((x) => OnBetterSolutionFound(new BetterSolutionEventArgs(solverName, currentStep, maximalSteps, bestObjValue, incumbmentValue)), null);
        }

        public event EventHandler<BetterSolutionEventArgs> BetterSolutionFound;

        private void OnBetterSolutionFound(BetterSolutionEventArgs e)
        {
            var handler = BetterSolutionFound;
            if (handler != null)
                handler(this, e);
        }


        #region IModelSolvingTracker member

        /// <summary>
        /// Nimmt ein OplModell entgegen, dessen Lösungsweg verfolgt werden soll
        /// </summary>
        /// <param name="model"></param>
        public void PassModel(Model model)
        {
            _model = model;
        }
        #endregion

    }
}

ModelGenerator: Zuständig für das Erzeugen eines für OPL/CPLEX verständliches Model aus unseren Modelinformationen.


using System;
using System.IO;
using ILOG.CPLEX;
using Moveo.Profahr.Optimization.BusinessLogic.Contract;
using ILOG.OPL;
using Moveo.Profahr.Optimization.Infrastructure;
using Moveo.Toolkit.CallResults;
using IloException=ILOG.Concert.IloException;

namespace Moveo.Profahr.Optimization.BusinessLogic.Impl
{
    /// <summary>
    /// Klasse zur Modellgenerierung von Opl Modellen
    /// auf Basis einer Konstruktor-injizierten OplFactory
    /// </summary>
    internal sealed class ModelGenerator : IModelGenerator
    {

        #region properties and fields

        /// <summary>
        /// Ausschließlich über die OplFactory darf das Modell und alle zugehörigen Elemente generiert werden
        /// </summary>
        public OplFactory OplFactory { get; private set; }

        /// <summary>
        /// Object einer Cplex.Callback abgeleiteten Klasse
        /// nimmet die Verlaufinformation der Optimierungsprozesses entgegen
        /// </summary>
        public Cplex.Callback Callback { get; private set; }

        /// <summary>
        /// ErrorHandler zur Fehlerbehandlung bei der Modellgenerierung und Abarbeitung
        /// </summary>
        private TextWriter CustomErrorHandler { get; set; }

        /// <summary>
        /// Modellösungsverfolger.
        /// </summary>
        private IModelSolvingTracker ModelSolvingTracker { get; set; }

       
        #endregion

        #region Constructors

        /// <summary>
        /// Modelgenerator auf Basis der übergebene OplFactory
        /// </summary>
        /// <param name="oplFactory"><see cref="OplFactory"/></param>
        /// <param name="callback"><see cref="Callback"/></param>
        /// <param name="customErrorHandler"><see cref="CustomErrorHandler"/></param>
        /// <param name="modelSolvingTracker">Modellösungsverfolger</param>
        public ModelGenerator(OplFactory oplFactory, Cplex.Callback callback, TextWriter customErrorHandler, IModelSolvingTracker modelSolvingTracker)
        {
            OplFactory = oplFactory;
            Callback = callback;
            CustomErrorHandler = customErrorHandler;
            ModelSolvingTracker = modelSolvingTracker;
        }

        #endregion


        #region public member

        /// <summary>
        /// Generiert mittels einer OplFactory das gesamt OplModell,
        /// dass zur Lösung der übergeben Modellinformationen genutzt werden kann.
        /// Erstellt Cplex
        /// Verknüpft Cplex mit Callback Objekt
        /// Erstellt OplModell
        /// Verknüpft Callback Objekt mit OplModell
        /// </summary>
        /// <param name="modelInfo"><see cref="ModelInfo"/></param>
        /// <returns>OplModel für die Lösung der übergebenen Modellinformationen</returns>
        public CallResult<Model> Generate(ModelInfo modelInfo)
        {
            // - CPLEX - initialisieren
            var oplCplex = CreateCplex(modelInfo);
            // wenn vorhanden, dann CallBack anhängen
            if (Callback != null)
            {
                oplCplex.Use(Callback);
            }

            // - OPL MODELL - aufbauen
            var oplErrorHandler = CreateErrorHandler();
            var oplModelSource = CreateModelSource(modelInfo.ModelFileName);

            var oplModel = CreateOplModel(oplErrorHandler, oplModelSource, oplCplex, modelInfo);
            try
            {
                oplModel.Generate();

            }
            catch (IloException ex)
            {
                return new CallResult<Model>().AddNewProblem(new CallResultExceptionProblem(ex.Message, ex));
            }


            // - MODEL - erstellen mit Modelinfo und erstelltem OplModel
            var model = new Model(oplModel, modelInfo);

	    // dem Modellösungsverfolger das Model mitteilen
            if (ModelSolvingTracker != null)
            {
                ModelSolvingTracker.PassModel(model);
            }
            return new CallResult<Model>(model);
        }


        #endregion

        
        #region private member

        /// <summary>
        /// Initialisierung eines Cplex Objektes über die OplFactory.
        /// Für die Cplex Engine Ausgaben wird ein Outputstream auf den 
        /// über <see cref="modelInfo"/> übergebenen <see cref="ModelInfo.EngineProtokollFileName"/> gesetzt.
        /// </summary>
        /// <param name="modelInfo"></param>
        /// <returns>Cplex</returns>
        private Cplex CreateCplex(ModelInfo modelInfo)
        {
            var oplCplex = OplFactory.CreateCplex();
            if (oplCplex != null)
                if (!string.IsNullOrEmpty(modelInfo.EngineProtokollFileName))
                {
                    var cplexOutputStream = new StreamWriter(modelInfo.EngineProtokollFileName);
                    oplCplex.SetOut(cplexOutputStream);
                }
            return oplCplex;
        }

        /// <summary>
        /// Initialisierung eines OplErrorHandlers mit/ohne Outputstream
        /// abhängig davon, ob modelInfo.ErrorProtokollFileName gefüllt ist
        /// </summary>
        /// <returns>OplErrorHandler</returns>
        private OplErrorHandler CreateErrorHandler()
        {
            return OplFactory.CreateOplErrorHandler(CustomErrorHandler);
        }

        /// <summary>
        /// Initialisiert eine OplModelSoucre aus dem übergebenen modelInfo.ModelFileName
        /// </summary>
        /// <param name="modelFileName">Dateiname des Hauptmodells</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        private OplModelSource CreateModelSource(string modelFileName)
        {
            if (string.IsNullOrEmpty(modelFileName))
                throw new ArgumentNullException("modelFileName");

            return OplFactory.CreateOplModelSource(modelFileName);
        }

        /// <summary>
        /// Initialisiert das Oplmodell
        /// </summary>
        /// <param name="oplErrorHandler">Erzeugt über CreateErrorHandler <see cref="OplErrorHandler"/></param>
        /// <param name="oplModelSource">Erzeugt über CreateModelSource <see cref="OplModelSource"/></param>
        /// <param name="oplCplex">Erzeugt über CreateCplex</param>
        /// <param name="modelInfo"><see cref="ModelInfo"/></param>
        /// <returns>OplModel</returns>
        private OplModel CreateOplModel(OplErrorHandler oplErrorHandler, OplModelSource oplModelSource, 
            Cplex oplCplex, ModelInfo modelInfo)
        {
            // ---------------     Hinweis  ! Undokumentiert innerhalb OPL !      --------------
            // Das Setzen des OPL OutputSreams kann nur vor der Erstellung der Objekte durch die Factory erfolgen
            // Die Einstellung wird sonst bei der Ausführung nicht beachtet
            if (!string.IsNullOrEmpty(modelInfo.OutputFileName))
            {
                var oplOutputStream = new StreamWriter(modelInfo.OutputFileName);
                OplFactory.SetOut(oplOutputStream);
            }


            var oplSettings = OplFactory.CreateOplSettings(oplErrorHandler);
            oplSettings.getExecutionController().enableAbort();
            oplSettings.IsWithNames = true;

            var oplModelDefinition = OplFactory.CreateOplModelDefinition(oplModelSource, oplSettings);

            var oplModel = OplFactory.CreateOplModel(oplModelDefinition, oplCplex);

            foreach (var dataFileName in modelInfo.DataFileNames)
            {
                // gleich zum nächsten Element springen, wenn dataFileName leer ist
                if (string.IsNullOrEmpty(dataFileName)) continue;
                // aus dem dataFileName eine weietre Datanquelle für das Modell generieren
                var oplDataSource1 = OplFactory.CreateOplDataSource(dataFileName);
                oplModel.AddDataSource(oplDataSource1);
            }

            return oplModel;

        }


        #endregion

    }
}

IModelSolver: Beschreibt die Fähigkeit ein Model zu lösen und, da von IModelSolvingBetterSolutionNotification geerbt wird, über den Lösungsfortschritt zu informieren.


using Moveo.Profahr.Optimization.BusinessLogic.Contract;
using Moveo.Profahr.Optimization.Infrastructure;
using Moveo.Toolkit.CallResults;

namespace Moveo.Profahr.Optimization.BusinessLogic.Impl
{
    /// <summary>
    /// Interface für Klassen, die ein gegebenes Modell <see cref="Model"/> lösen können
    /// </summary>
    internal interface IModelSolver : IModelSolvingBetterSolutionNotification
    {
        /// <summary>
        /// Lösung eines OPL Modells <see cref="Model"/>
        /// </summary>
        /// <param name="model"><see cref="Model"/></param>
        /// <returns><see cref="SolutionInfo"/></returns>
        CallResult<SolutionInfo> Solve(Model model);
    }
}

ModelSolver: Die konkrete Implementierung von IModelSolver.


using System;
using Moveo.Profahr.Optimization.BusinessLogic.Contract;
using Moveo.Profahr.Optimization.Infrastructure;
using Moveo.Toolkit.CallResults;

namespace Moveo.Profahr.Optimization.BusinessLogic.Impl
{
    /// <summary>
    /// Löst ein übergebenes Oplmodell und stellt ein EventHandler BetterSolutionFound bereit
    /// </summary>
    internal sealed class ModelSolver : IModelSolver
    {
        /// <summary>
        /// Erstellt eine neue Instanz der Klasse.
        /// Abonniert BetterSolutionFound des übergebenen <see cref="IModelSolvingBetterSolutionNotification"/>, 
        /// um es wiederum nach außen verfügbar zu machen.
        /// </summary>
        /// <param name="modelSolvingBetterSolutionNotification"><see cref="IModelSolvingBetterSolutionNotification"/></param>
        public ModelSolver(IModelSolvingBetterSolutionNotification modelSolvingBetterSolutionNotification)
        {
            modelSolvingBetterSolutionNotification.BetterSolutionFound += (sender, e) => OnBetterSolutionFound(e);
        }


        /// <summary>
        /// Abonniert BetterSolutionFound des übergebenen <see cref="IModelSolvingBetterSolutionNotification"/>, 
        /// und macht es nach außen verfügbar.
        /// </summary>
        public event EventHandler<BetterSolutionEventArgs> BetterSolutionFound;

        private void OnBetterSolutionFound(BetterSolutionEventArgs e)
        {
            var handler = BetterSolutionFound;
            if (handler != null)
                handler(this, e);
        }


        /// <summary>
        /// Lösung eines OPL Modells <see cref="Model"/>
        /// </summary>
        /// <param name="model"><see cref="Model"/></param>
        /// <returns><see cref="SolutionInfo"/></returns>
        public CallResult<SolutionInfo> Solve(Model model)
        {
            return new CallResult<SolutionInfo>(new SolutionInfo(model.OplModel.Main()));
        }

    }
}

IOptimizationManager: Beschreibt den Einsprungspunkt für die Optimierungsvorgänge (eine Art Fassade für die vorherigen Klassen).


using Moveo.Profahr.Optimization.Infrastructure;

namespace Moveo.Profahr.Optimization.BusinessLogic.Contract
{
    /// <summary>
    /// Führt die Optimierung zu einem per Modellinfo übergebenen Optimierungsproblems aus.
    /// </summary>
    public interface IOptimizationManager : IModelSolvingBetterSolutionNotification, IModelSolvingEndNotification
    {
        /// <summary>
        /// Starten eines Optimierungsprozesses
        /// </summary>
        /// <param name="modelInfo">Informationen <see cref="ModelInfo"/>, die das zu lösende Optimiernugsproblem beschreiben</param>
        void Run(ModelInfo modelInfo);
    }
}

OptimizationManager: Konkrete Implementierung für die eben aufgezeigte Schnittstelle.


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Moveo.Profahr.Optimization.BusinessLogic.Contract;
using Moveo.Profahr.Optimization.Infrastructure;
using Moveo.Toolkit.CallResults;
using ErrorEventArgs = Moveo.Profahr.Optimization.Infrastructure.ErrorEventArgs;

namespace Moveo.Profahr.Optimization.BusinessLogic.Impl
{
    internal class OptimizationManager : IOptimizationManager
    {
        // Modellinformation, dazugehöriger Modellgenerator und Solver
        public IModelGenerator ModelGenerator { get; set; }
        public IModelSolver ModelSolver { get; set; }
        public IModelSolverErrorHandler ModelSolverErrorHandler { get; set; }
        private readonly List<ModelSolverMessage> _modelSolverMessages;

        /// <summary>
        /// Nimmt die übergebene Modellinformation, den dazugehörigen Modellgenerator und den Solver entgegen
        /// Stellt außen einen Eventhandler bereit für das Event "BetterSolutionFound" des Solvers betreit
        /// </summary>
        /// <param name="modelGenerator">Object, dass aus den Informationen ein Modell generiert</param>
        /// <param name="modelSolver">Object, dass das aus den Informationen generierte Modell lösen kann</param>
        /// <param name="modelSolverErrorHandler">Object, dass Fehler, Warnungen etc. aus dem Lösungsprozess entgegennimmt</param>
        public OptimizationManagerBase(IModelGenerator modelGenerator, IModelSolver modelSolver, IModelSolverErrorHandler modelSolverErrorHandler)
        {
            ModelGenerator = modelGenerator;
            ModelSolver = modelSolver;
            ModelSolverErrorHandler = modelSolverErrorHandler;
            _modelSolverMessages = new List<ModelSolverMessage>();

            // modelSolverErrorHandler meldet Fehler und Warungen, 
            // die aus der Oplklasse während der Modellerstellung oder des Lösungsprozesses kommen
            modelSolverErrorHandler.SolverError += ModelSolverErrorHandler_SolverError;
            modelSolverErrorHandler.SolverWarning += ModelSolverErrorHandler_SolverWarning;

            // modelSolver meldet sich in "gewissen Abständen", die Opl intern bestimmt sind,
            // mit dem Stand der Lösung zurück
            modelSolver.BetterSolutionFound += (sender, e) => OnBetterSolutionFound(e);
        }

        


        public virtual void Run(ModelInfo modelInfo)
        {
            // Liste der Messages (i.d.R Error / Warning) vom Solver zurücksetzen
            ModelSolverMessagesClear();

            try
            {
                var runResult = OptimizationRunner.Run(modelInfo, ModelGenerator,
                                                          ModelSolver);
                if(runResult.IsOK)
                {
                    OnCompleted(new CompletedEventArgs(runResult.ReturnValue));
                }
                else
                {
                    // ToArray weil unveränderbare Copy
                    OnError(new ErrorEventArgs(new CallResult<SolutionInfo>(runResult), _modelSolverMessages.ToArray()));
                }
            }
            catch (Exception ex)
            {
                OnError(
                    new ErrorEventArgs(
                        new CallResult<SolutionInfo>(new[] {new CallResultExceptionProblem(ex)}), _modelSolverMessages.ToArray()));
            }
        }


        #region Delegates für die Events des modelSolverErrorHandler

        /// <summary>
        /// Delegate für den EventHandler modelSolverErrorHandler.SolverError
        /// Nimmt Fehler aus dem Lösungsprozess asynchron entgegen
        /// </summary>
        /// <param name="sender">Wird hier nicht verwendet</param>
        /// <param name="e"></param>
        private void ModelSolverErrorHandler_SolverError(object sender, ModelSolverErrorHandlerEventArgs e)
        {
            AddModelSolverMessage(e.ModelSolverMessage);
        }


        /// <summary>
        /// Delegate für den EventHandler modelSolverErrorHandler.SolverWarning
        /// Nimmt Warnungen aus dem Lösungsprozess asynchron entgegen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ModelSolverErrorHandler_SolverWarning(object sender, ModelSolverErrorHandlerEventArgs e)
        {
            AddModelSolverMessage(e.ModelSolverMessage);
        }

        #endregion

        public event EventHandler<BetterSolutionEventArgs> BetterSolutionFound;

        protected virtual void OnBetterSolutionFound(BetterSolutionEventArgs e)
        {
            var handler = BetterSolutionFound;
            if (handler != null)
                handler(this, e);
        }

        public event EventHandler<CompletedEventArgs> Completed;

        protected virtual void OnCompleted(CompletedEventArgs e)
        {
            var handler = Completed;
            if (handler != null)
                handler(this, e);
        }

        public event EventHandler<ErrorEventArgs> Error;

        protected virtual void OnError(ErrorEventArgs e)
        {
            var handler = Error;
            if (handler != null)
                handler(this, e);
        }

        private IEnumerable<CallResultProblem> GetModelSolverErrorMessagesAsCallResultProblems()
        {
            return GetModelSolverErrorMessages().Select(error => new CallResultProblem(error.ToString()));
        }

        #region private Member

        /// <summary>
        /// Bereinigt die Liste der Fehler / Warnung des Optimierungsprozesses
        /// </summary>
        private void ModelSolverMessagesClear()
        {
            _modelSolverMessages.Clear();
        }


        /// <summary>
        /// Fügt einen der Fehler / Warnung des Optimierungsprozesses in die private Liste ein
        /// </summary>
        private void AddModelSolverMessage(ModelSolverMessage modelSolverMessage)
        {
            _modelSolverMessages.Add(modelSolverMessage);
        }

        private IEnumerable<ModelSolverMessage> GetModelSolverErrorMessages()
        {
            return _modelSolverMessages.Where( message=>message.Typ==ModelSolverMessageTyp.Error);
        }

        #endregion
    }
}

Ich habe hier nur einige für das Beispiel wichtige Schnittstellen und Klassen gepostet.
Zu betonen ist, dass es sich hierbei noch um einen Entwurf handelt.

Der Problemkern liegt meiner Meinung nach in der Klasse ModelSolverCallback, welche zum einen eine spezielle Ableitung der Drittanbieterklasse
darstellt und zum anderen noch zwei unserer eigenen Interfaces implementiert; nämlich eines zur Benachrichtigung über den Lösungsfortschritt und
zum anderen eines für das Aufnehmen eines Models. Die beiden Interfaces wurden deshalb zu zweien und nicht zu einem, da das Aufnehmen eines Models
und die Benachrichtigung über den Fortschritt nicht unbedingt was mit einander zu tun haben. (Interfacesegregation, oder?)

So.... und wenn ich nun irgendwo das Interface IModelSolvingBetterSolutionNotification verwende und anderswo IModelSolvingTracker, dann möchte ich die
selbe Instanz übergeben.
Und das ist mit container.Register(...) möglich, mit Xml-Config jedoch nicht.

Natürlich kann hier auch ein Designfehler vorliegen, dann klärt uns bitte auf.
(?Denkbar wäre eine Aggregation zwischen ModelSolverCallback und einer Instanz einer separaten Notificatorklassen?)

Danke und viele Grüße,
Kani

10.04.2010 - 10:35 Uhr

Hallo zusammen,

mit LightCore ist es ja möglich, per Code für zwei (oder mehr) Interfaces die selbe Instanz zu registrieren:


interface IReadableRepsoitory
{
}

interface IWriteableRepository
{
}

interface IRepository : IReadableRepository, IWriteableRepository
{
}

class MyRepository : IRepository
{
}

class Program
{
    public static void Main()
    {
        var containerBuilder = new ContainerBuielder();
        containerBuilder.Register<IRepostory>().StirbLansamMit<SingletonLifecycle>();
        containerBuilder.Register<IReadableRepository>(c => c.Resolve<IRepository>());
        containerBuilder.Register<IWriteableRepository>(c => c.Resolve<IRepository>());

        var container = containerBuilder.Build();
        var a = container.Resolve<IReadableRepository>();
        var b = container.Resolve<IWriteableRepsoitory>();
        var b = container.Resolve<IRepository>();

        a.ReferenceEquals(b); // == true
        b.ReferenceEquals(c); // == true
    }
}

Meine Frage ist nun, wie würde ich das über eine Xml-Konfiguration abbilden können....?

Grüße,
Kani

// edit: Beispiel angepasst

10.04.2010 - 10:28 Uhr

Hallo Kanti,

kann es sein, dass deine Assembly "SqlServer" nicht im Ausgabeverzeichnis des Programms zu finden ist, also dass auch LightCore sie nicht finden kann?

Grüße,
Kani

10.04.2010 - 10:21 Uhr

Hallo zusammen,

ich persönlich finde die übergabe von Konstruktorargumenten im Resolve genauso unpassend, wie die Registrierung mit WithName (was Golo als Bug von microkerneln bezeichnet hatte).

An der Stelle, wo ich ein container.Resolve<IMyInterface>() absetze, habe ich keine Ahnung über die Konstruktorparameter. Alles was die Implementierung an dynamischen Parametern (wie Port, Ip, o.ä.) braucht, sollte über das Interface als Properties bekannt gegeben werden. Sollten diese Parameter nicht für jede Implementierung passend sein, dann muss ein weiteres, spezialisierteres Interface angelegt werden.

Ich finde es nur etwas widersprüchlich, dass auf der einen Seite Register(..).WithName() entfernt bzw. auf obsolete gesetzt werden soll, auf der anderen Seite jedoch dynamische Konstruktorargumente möglich gemacht werden sollen.

Wenn man sich mal folgendes Beispiel anschaut:


interface IDataSource
{
}

class SqlDataSource : IDataSource
{
    public SqlDataSource(string connectionString)
    {
    }
}

class XmlDataSource : IDataSource
{
    public SqlDataSource(XmlDocument doc)
    {
    }
}

class Program
{
    public static void Main()
    {
        var containerBuilder = new ContainerBuilder();
        containerBuilder.Register<IDataSource, XmlDataSource>();

        var container = containerBuilder.Build();
        
        // hier weiß ich nichts von einem Connectionstring, 
        // auch weiß ich nichts von einem XmlDocument,
        // da ich ja auch nicht weiß, welche DataSource-Implementierung 
        // verwendet wird
        var dataSource = container.Resolve<IDataSource>();
    }
}

oder folgendes:


interface IDataSource
{
}

interface IDataSourceHost
{
}

class MyDataSourceHost : IDataSourceHost
{
    public MyDataSourceHost(IDataSource dataSource)
    {
        // ... hier habe ich bereits eine initialisierte IDataSource....
    }
}

class SqlDataSource : IDataSource
{
    public SqlDataSource(string connectionString)
    {
    }
}

class XmlDataSource : IDataSource
{
    public XmlDataSource(XmlDocument doc)
    {
    }
}

class Program
{
    public static void Main()
    {
        var containerBuilder = new ContainerBuilder();
        containerBuilder.Register<IDataSource, XmlDataSource>();
        containerBuilder.Register<IDataSourceHost, MyDataSourceHost>();

        var container = containerBuilder.Build();
        
        // selbes Problem wie im vorherigen Beispiel.... ich weiß nichts über
        // ConnectionStrings oder XmlDocuments..... wie denn auch,
        // ich kenne die Implementierung nicht.... ähnlich wie bei Mocks in UnitTests
        var dataSource = container.Resolve<IDataSourceHost>();
    }
}

Da ein Konstruktor nicht im Interface unterbringbar ist (was auch nicht nötig ist), kann ich nirgends davon ausgehen, dass bei einem Resolve von irgendeinem Interface genau die dann dort übergebenen Argumente zu einem Konstruktor passen....

Vielleicht sehe ich das ja auch völlig falsch.... Dann helft mir bitte auf die Sprünge 😉.

Grüße,
Kani

09.04.2010 - 17:33 Uhr

Hallo Golo,
Hallo Peter,

vielen Dank für die Antworten.

@Golo:
Die Idee, dass ich ein eigenes Interface implementiere ist mir auch schon gekommen, jedoch würde dann, wie du ja auch geschrieben hast, ein Typecast nötig sein:


class MyTextWriter : TextWriter, ITextWriter
{
}

class MyTextWriterConsumer
{
    public MyTextWriterConsumer(ITextWriter textWriter)
    {
        // und folgender Cast stört mich halt
        this.thirdPartyComponent.TextWriter = (TextWriter)textWriter;
    }
}

Daher finde ich Peters Lösungsvorschlag besser, da ich hier typsicher und ohne casts arbeiten kann.

Mir ist dann in dieser Sache erstmal geholfen, danke nochmal an euch beide.

Ich habe noch ein zwei weitere Fragen zu LightCore, diese werde ich jedoch in gesonderten Threads posten.

Grüße,
Kani

08.04.2010 - 16:53 Uhr

Hallo Peter,

wenn ich meinen TextWriter auf den .NET-TextWriter registriere, dann wird jedesmal wenn irgendwo ein TextWriter erwartet wird mein TextWriter genommen.
Und ganau das ist mein Problem.... das will ich nicht.

Wenn ich an meinem TextWriter jedoch noch ein Interface registrieren würde und dieses dann in meiner Klasse im ctor erwarten würde, müsste ich aber beim Weiterreichen an die Drittanbieterkomponente einen typecast durchführen und das fällt aus (typecasts sind böse 😉 ).

Was wäre, wenn ich vom .net-TextWriter eine Klasse ableite, diese als abstrakt markiere und meinen konkreten TextWriter von eben dieser Klasse ableiten würde?
Auf meine abstrakte Klasse (die ja auch ein TextWriter ist), würde ich dann meine konkreten TextWriter registrieren und in der Klasse, die die Drittanbieterkomponente hostet würde ich im ctor meine abstrakte TextWriter-Klasse erwarten....:


abstract class ThirdPartyTextWriter : TextWriter
{
}

class MyTextWriter : ThirdPartyTextWriter
{
    // ... my impl
}

class ThirdPartyHost : IThirdPartyHost
{
    public ThirdPartyHost(ThirdPartyTextWriter textWriter)
    {
        this.myThirdPartyComponent.TextWriter = textWriter;
    }
}

//...
class Program
{
    public void Main()
    {
        var containerBuilder = new ContainerBuilder();
        containerBuilder.Register<ThirdPartyTextWriter, MyTextWriter>();
        containerBuilder.Register<IThirdPartyHost, ThirdPartyHost>();
        containerBuilder.Register<TextWriter>(c => Console.Out);

        var container = containerBuilder.Build();
        var tpHost = container.Resolve<IThirdPartyHost>(); // hier ist mein TextWriter injiziert

        container.Resolve<TextWriter>().WriteLine("Hallo Welt!"); // schreibt auf die Console...
    }
}

Grüße,
Kani

08.04.2010 - 15:50 Uhr

Hallo Peter,

uffffff.........

Das haut mich erstmal kurz um....
Jedoch verstehe ich die Gedanken von Golo und sehe es auch ein.

Dein Beispiel, wie ich mein TextWriterproblem lösen könnte, leuchtet mir ein, passt aber glaube ich nicht wirklich zum meinem Problem,
da mein TextWriter kein Interface, sondern die Klasse TextWriter aus dem .NET-Framework. Das liegt daran, dass ich die TextWriter-Instanz an eine Drittanbieterkomponente weiterreichen muss:


class MyTextWriter : TextWriter
{
    // ... meine impl
}

class My3rdPartyWrapper : IMyThirdPartyWrapper
{
    public My3rdPartyWrapper(TextWriter textWriter)
    {
        this.myThirdPartyComponent.TextWriter = textWriter;
    }
}

Ich hatte schon drüber nachgedacht, einen Wrapper oder eine Factory für MyTextWriter zu implementieren:


class MyTextWriter : TextWriter
{
    // ... meine impl
}

interface ITextWriterProviderFor3rdParty
{
    TextWriter GetTextWriter();
}

class MyTextWriterProvider : ITextWriterProviderFor3rdParty
{
    public TextWriter GetTextWriter()
    {
        return new MyTextWriter();
    }
}

class My3rdPartyWrapper : IMyThirdPartyWrapper
{
    public My3rdPartyWrapper(ITextWriterProviderFor3rdParty textWriterProvider)
    {
        this.myThirdPartyComponent.TextWriter = textWriterProvider.GetTextWriter();
    }
}

Ich finde nur, dass diese Lösung auch nicht das Gelbe vom Ei ist, da ich in dem GetTextWriter() ein "new MyTextWriter()" zu stehen habe....
Und mein Ziel ist es, sämtliche Objekterzeugung (ausgenommen primitive Datenstrukturen, DTOs und DomainObjects) über LightCore laufen zu lassen....

Wobei andererseits ein DI-Container keine vollständige Ablösung von Factories darstellen kann.... Beispielsweise für Dynamische Objekterzeugung nach Parameterwert (wenn ich bei GetText z.B. noch ein Enum oder string oder sonstwas mitgeben würde)...... da braucht man einfach eine Factory, oder nicht?

Was meinst du/ihr dazu?

Grüße,
Kani

08.04.2010 - 13:16 Uhr

Hallo Leute,

gegeben sei folgender Code:


using LightCore;

class MyClassA : IInterfaceA
{
}

class MyClassA1 : IInterfaceA
{
}


class MyClassB : IInterfaceB
{
    public MyClassB(IInterfaceA dependencyA)
    {
        // ...
    }
}


class Program
{
    public static void Main()
    {
        var containerBuilder = new ContainerBuilder();

        containerBuilder.Register<IInterfaceA, MyClassA>();
        containerBuilder.Register<IInterfaceA, MyClassA1>().WithName("A1_SpecialCase");

        containerBuilder.Register<IInterfaceB, MyClassB>();
        containerBuilder.Register<IInterfaceB>(c => new MyClassB(c.Resolve<IInterfaceA>("A1_SpecialCase")).WithName("B1_SpecialCase");

        var container = containerBuilder.Build();

        // .....
    }
}



Wenn ich nun ein container.Resolve<IInterfaceB>() aufrufe, dann wird MyClassB erzeugt und bekommt im ctor als Argument eine Instanz von MyClassA injiziert.
Rufe ich container.Resolve<IInterfaceB>("B1_SpecialCase") auf, dann wird auch MyClassB erzeugt, bekommt jedoch MyClassA1 injiziert.

Meine Frage ist nun, wie kann ich das über die LightCore-Xml-Configuration abbilden?
Dort kann man zwar Aliase/Names für Mappings angeben, diese jedoch keinem anderen Mapping als ctor-Parameter angeben. Und somit wäre die Sache mit new MyClassB(c.Resolve<IInterfaceA>("A1_SpecialCase")) nicht möglich... oder?

Mein Beispiel ist jetzt nicht gerade ein Real-World-Problem, ich stehe jedoch vor einer ähnlichen Situation, wo ich eine Klasse von TextWriter ableiten muss und ich jetzt nicht überall diese Klasse als Textwriter verwenden will, sondern nur an ein zwei bestimmten Stellen, wo im Ctor ein TextWriter erwartet wird. Dafür habe ich dann diesem Mapping (TextWriter zu meinem TextWriter) einen Alias/Name verpasst. Über Container.Register(...) ist das wie oben erwähnt alles kein Problem, nur eine Xml-Config wäre damit doch nicht möglich, oder?

Grüße,
Kani

06.04.2010 - 20:12 Uhr

Der Code wird auch funktionieren, solange du nicht im DoWork-Delegate auf den BackgroundWorker zugreifst, da dieser bereits verworfen sein könnte (sein wird).

Der Stil des Codes ist halt nicht schön und auch unsicher.

P.S.: Ein Aufruf von Dispose hat keine Auswirkungen auf die Garbage Collection...
Dispose sorgt lediglich dafür, dass Ressourcen (wie z.B. Threadhandles o.ä. freigegeben werden).

06.04.2010 - 19:30 Uhr

Hallo impact,

das führt sicherlich nicht zu dem von dir erwarteten Ergebnis,
da RunWorkerAsync() ja sofort wieder zurückkehrt, nachdem der Hintergrundthread gestartet wurde.... und anschließend wird der using-block verlassen und der backgroundworker disposed, der ja aber theoretisch noch in deinem DoWork-Delegate verwendet wird....

Grüße,
Kani

11.01.2010 - 15:21 Uhr

Hallo Golo,

ich habe diesen Dienst vor etwas längerer Zeit selbst genutzt und war sehr zufrieden. Den Geschäftsführer kenne ich persönlich und aus meiner Sicht ist er sehr seriöser, sowie auch seine Firma.

Viele Grüße,
Kani

16.03.2009 - 22:50 Uhr

Hallo ugur.karatas,

das Problem ist, dass der OLE-DB Treiber für Excel standardmäßig denkt, dass in der ersten Zeile die Spaltenüberschriften stehen. Da dies bei dir nicht der Fall zu sein scheint, musst du ihm dies mitteilen.
Füge dazu zu den ExtendedProperties im Connectionstring ein "HDR=No" hinzu:


connection.ConnectionString = "provider=Microsoft.Jet.OLEDB.4.0;data source=" + _sPath + ";Extended Properties=Excel 8.0;HDR=No";

Grüße,
Kani

01.01.2009 - 12:44 Uhr

Ein frohes und gesundes Jahr 2009 euch allen!

Grüße,
Kani

31.12.2008 - 15:46 Uhr

@all:
Ich wünsche dem gesamten Forum (+Mitglieder 😉 ) einen guten Rutsch ins Jahr 2009!

Grüße,
Kani

11.12.2008 - 20:40 Uhr

Dann musst du mal ganz freundlich einen Arbeitgeber fragen 😃

Genau... so hab ich's auch gemacht. Privat wäre es mir auch etwas zu fett.

Grüße,
Kani

05.12.2008 - 16:59 Uhr

/// <summary>
/// Ermittelt die Anzahl der Erfassten Vitalwerte in <paramref name="vitalSigns"/> zu jeder Tageszeit.
/// </summary>
/// <param name="vitalSigns">Vitalwerterfassungskopf</param>
/// <returns>Array mit den Anzahlen der erfassten Vitalwerte zu den jeder Tageszeit</returns>
/// <remarks>
/// Im Array folgen für jedes Vitalzeichen (<see cref="VitalSignFlag"/>) alle sechs Tageszeiten (<see cref="Daytime"/>).<br/><br/>
/// 
/// ACHTUNG: Falls <paramref name="vitalSigns"/> noch transient ist, wird für jede Tageszeit 0 zurückgegeben!
/// </remarks>
private int[] GetCountsOfDaytimeSetFlags(VitalSigns vitalSigns)
{
    var result = new object[ALL_VITALSIGNFLAGS.Length*6];

    if (!vitalSigns.IsTransient())
    {
        var dict = new Dictionary<VitalSignFlag, IDictionary<Daytime, int>>();
        foreach (var vitalSignFlag in ALL_VITALSIGNFLAGS)
        {
            var daytimeDict = new Dictionary<Daytime, int>();
            foreach (var daytime in ALL_DAYTIMES)
                daytimeDict.Add(daytime, 0);
            dict.Add(vitalSignFlag, daytimeDict);
        }

        var list = GetIListByHQL<object[]>("SELECT dd.Daytime, count(vv.SystolicValue), count(vv.BeatsPerMinute), count(vv.Level), count(vv.Degree), count(vv.Kilograms), count(vv.Meters) FROM VitalValues vv, DaytimeDefinition dd WHERE vv.TimeInMinutesAfterMidnight >= dd.TimeFrom AND ((dd.TimeFrom < dd.TimeTo and vv.TimeInMinutesAfterMidnight <= dd.TimeTo) or (dd.TimeFrom > dd.TimeTo and vv.TimeInMinutesAfterMidnight >= dd.TimeTo)) AND vv.VitalSigns = :vs GROUP BY dd.Daytime ORDER BY dd.Daytime", "vs", vitalSigns);
        foreach (var row in list)
        {
            var daytime = (Daytime)row[0];
            foreach (var vitalSignFlag in ALL_VITALSIGNFLAGS)
                dict[vitalSignFlag][daytime] = Convert.ToInt32(row[((int) vitalSignFlag) + 1]);
        }

        var counter = 0;
        foreach (var outerPair in dict)
            foreach (var innerPair in outerPair.Value)
                result[counter++] = innerPair.Value;
    }
    else
    {
        for (var i = 0; i < result.Length; i++)
            result[i] = 0;
    }

    return Array.ConvertAll(result, o => Convert.ToInt32(o));
}

ich glaub, dass sollte an eine andere stelle verschoben werden....

29.11.2008 - 12:43 Uhr

Hey Leute,

wollt mal fragen, wen man hier aus dem Forum auf der BASTA! 2009 Spring im Februar antreffen könnte...

Grüße,
Kani

13.08.2008 - 21:42 Uhr

Hallo Rainbird,

danke für die Info.

Werde dann das ActiveX-Control verwenden.

Über die API kann man Felder in PDF-Formulare auch mit Werten aus der Datenbank füllen. Soweit ich weiss, sind da auch Auswahl- und ComboBox-Felder möglich.

Meinst du die API des ActiveX-Controls oder die einer anderen Komponente wie iTextSharp?
Falls die API des Controls gemeint ist, wo finde ich die Doku dazu? Auf den Seiten von Adobe?

Grüße,
Kani

13.08.2008 - 14:50 Uhr

Hi,


public static int Age(DateTime birthDay, DateTime refDate)
{
return (refDate.Year - birthDay.Year) - (((refDate.Month == birthDay.Month && refDate.Day < birthDay.Day) || (refDate.Month < birthDay.Month)) ? 1 : 0);
}

...
Age(new DateTime(2000, 2, 29), DateTime.Today));

08.08.2008 - 14:43 Uhr

Hi Leute,

Aber so haben wir es gerne.
Leute, die nach erkennen des Problems die Lösung selber suchen, und hier Posten.

Da sollten sich andere ein Beispiel dran nehmen, und das ist nicht ironisch gemeint.

Ich kann FZelle nur zustimmen! Mir hat der letzte Post von Loewchen0507 z.B. eben sehr schnell geholfen. Danke!

Grüße,
Kani

04.08.2008 - 08:12 Uhr

Hallo Rainbird,

ich ahnte, dass es auf PDF hinauslaufen würde 😉.
Ist ja auch ok. Das was mich aber eben daran stört, ist die Adobe Acrobat Professional Lizenz, die der Kunde kaufen müsste...

Aber gut, wenn es wirklich die einzige vernünftige (und relativ zeitsparende) Lösung ist, dann muss es eben so sein.

Zu dem ActiveX-Steuerelement:
Haben die das nicht seit Adobe Reader 8 nicht mehr mitgeliefert bzw. die Entwicklung eingestellt?

Grüße und vielen Dank,
Kani

03.08.2008 - 15:47 Uhr

Hallo Bit2_Gosu,

wenn man zum Beispiel im Catch-Block ein "return" zu stehen hat.

Oft gibt es auch dass Konstrukt try...finally, also ohne einen zugehörigen catch-Bock. Würde man die Anweisung hier hinter dem try... bock schreiben und es tritt eine exception auf, würde die Anweisung nicht erreicht werden.
Oder aber man hat keinen generellen catch-Block und es kommt eine unerwartete Exception.......

Grüße,
Kani

03.08.2008 - 15:12 Uhr

Hallo Rainbird,

erstmal danke für deine Antwort.

Das gesuchte Control soll sich in unsere bestehende Anwendung integrieren.
Die damit erstellten Formulare werden dann von unseren Kunden innerhalb des Programms ausgefüllt.
Beispiele für solche Formulare sind z.B. der Psycho-Sozialbericht.

Das Speichern und Laden der Daten der Formulare würde von unserem Programm übernommen werden. (Datenbank)

Bei InfoPath ist das Problem, dass es eine eigenständige Anwendung ist und unsere Kunden zusätzlich Geld kosten würde.

bei InfoPath geht es keineswegs um Papierformulare, genausowenig wie bei PDF. Trotzdem sind InfoPath und PDF die Technologieen, mit denen meistens solche ausfüllbaren Formulare gemacht werden.

Das ist mir schon klar. Ich meinte in unserem Falle sind es Papierfomulare.
Bisher füllen unsere Kunden diese Formulare eben noch mit Kugelschreiber/Bleistift aus.
Wir könnten sicherlich die Datenfelder der Formulare in Masken packen, den Nutzer ausfüllen lassen und als Report das "Papierformular" ausgeben, welches der Kunde dann zum Amt schickt. Da es jedoch hunderte verschiedene Formulare gibt, wären wir in drei Jahren noch damit beschäftigt alle Formulare nachzubauen.
Und man müsste jedesmal zwei Layouts anlegen; einmal das ausfüllbare Form und den zu druckenden Report.

Ich stelle mir sowas wie einen "Reportdesigner" vor, mit dem man eben Formulare entwerfen kann, die den Papierformularen gleichen, die der Benutzer dann ausfüllen, speichern und drucken kann.
Mit diesem Designer können die Kunden dann die Formulare auch selbst entwerfen.

Grüße,
Kani

03.08.2008 - 10:21 Uhr

Hallo soxxing,

meiner Meinung nach ist ein Tattoo deine Sache. Es kommt doch schließlich auf die Qualität deiner Arbeit an. Bei uns in der Firma ist das Äußere (Tattoos, Piercings etc.) kein Einstellungskriterium.

Zum Kundenkontakt:
Selbst in der "reinen" Entwicklungsabteilung, sollte man die wichtigkeit des Kundenkontaktes nicht unterschätzen. Schließlich ist der Kunde derjenige, der das Produkt später benutzen wird. Niemand anderes kann dir besser beschreiben, wie er arbeitet und was er sich von der Software wünscht.

Grüße,
Kani

// EDIT: Lass dir doch ein "microsoft" in den Nacken tätowieren 😉

02.08.2008 - 22:28 Uhr

Hi Leute,

ich suche ein Win-Forms-Control, mit dem ich Formulare entwerfen (nicht WindowsForms; eher e-Forms) und später auch anzeigen und ausfüllen kann. Also sowas wie: man erstellt ein pdf-dokument, füllt dies aus und speichert die eingetragenen werte auch noch irgendwo ab (z.B. Datenbank).

Wichtig hierbei wäre noch, dass z.B. Auswahlfelder (Comboboxen) auf dem Formulare werte aus der Datenbank enthalten sollen. Also der Nutzer soll z.B. die Möglichkeit haben eine Bewohner-ComboBox aufs Formulare zu packen, wo er später beim Ausfüllen dann die Bewohner auswählen kann...

Ich hatte so einen Dokumenten/Formularedesigner bereits schon mal in SAL (Gupta SQL-Windows) programmiert. Ich hoffe, dass es für .NET bereits eine Komponente/ein Control gibt (ob kommerziell ist dabei egal), denn das nochmal in .NET zu programmieren, dazu fehlt mir die Zeit.

Ich meine aber keine Reportingkomponente. Es geht wirklich um "Papier-Formulare", die der Nutzer entwerfen und am Bildschirm ausfüllen kann => sowie z.B. in InfoPath.

Danke schonmal für die hoffentlich zahl- sowie hilfreichen Antworten 😉

Grüße,
Kani

12.05.2008 - 15:39 Uhr

myCSharp.de Rulez

Grüße,
Kani

03.05.2008 - 21:59 Uhr

Na, hat da jemand angst vor Silverlight? 🙂

hehe, sieht wohl ganz danach aus... aber so haben wenigstens alle was davon (mmhh, naja, außer vielleicht ms 🤔 )

Grüße,
Kani

29.04.2008 - 20:11 Uhr

Hallo timmi,

vielen Dank für den Tip und die Links!

Grüße,
Kani

28.04.2008 - 09:52 Uhr

Hallo antoschka,

als Doku nutze ich die mit NHibernate beigelegte (an manchen stellen wirklich etwas spärliche) Hilfe.
Und zur Einarbeitung nutze ich als Ebook "NHibernate in Action". Naja und eben das NH-Forum. Dort findet man fast zu jeder Frage eine Antwort.

Zu deinem Problem. Ich denke, vielleicht solltest du dein BusinessObject nicht auf die View schauen lassen und es statt dessen auf die Tabellenstruktur anpassen. Da ich allerdings nicht weiß, wie komplex das Tabellenmodell (für diesen einen Bereich) jetzt genau ist, weiß ich auch nicht, ob es sich vielleicht doch lohnen würde eine zusätzliche Schicht für die Speicherlogik einzuführen...

Wenn du magst, kannst du mir ja mal nen Auszug per PM schicken, falls du es hier nicht posten willst/kannst/darfst.

Grüße,
Kani

27.04.2008 - 09:24 Uhr

Hallo antoschka,

wenn ein businessobject sich über mehrere tabellen erstreckt und du ohne eine zusätzliche Schicht mit Services, die dann das Speichern übernehmen, arbeiten willst, dann müsstes du deine businessobjekte nochmal einem redesign unterziehen. über generalisierung und assotiationen sollte das alles regelbar sein. und eine extra schicht für das speichern manuell zu erstellen halte ich für übertrieben, da nhibernate selbst sich sehr gut um das gespeichere kümmern kann. es muss eben alles nur richtig konfiguriert und gemappt sein.

hoffe ich konnte helfen!

Grüße,
Kani

24.04.2008 - 08:49 Uhr

Super, danke!

Genau sowas habe ich gesucht!

Wiedereinmal vielen Dank an herbivore!!!

Grüße,
Kani

24.04.2008 - 08:40 Uhr

Hi Leute,

folgender Code sei gegeben:


public interface IMyInterface
{
    // ...
}

class MyClass : IMyInterface
{
    // IMyInterface impl.
}

//.... irgendwo später im code

IList<IMyInterface> GetSomething()
{
    IList<MyClass> myClasses = SomeOtherClass.GetSomething(); // Rückgabetyp ist IList<MyClass>
    //...
    return myClasses; // ERROR!
}

Dass in der letzten Zeile ein Compilterfehler auftreten muss ist mir völlig klar, da die Typen (IList<IMyInterface> und IList<MyClass>) nicht wirklich zueinander passen.
Gibt es einen Weg dies doch irgendwie hinzubekommen? Also die Typen passend zu machen.
Die Typparameter sind schließlich kompatibel zueinander. Ich glaub in Java gibt es für sowas wildcards o.ä. . (Ja ich weiß wir sind hier bei C#; ich bin auch kein Java-Verfechter oder sowas... soll nur ein Hinweis darauf sein, was ich meine 8o )

Bin für jede Antwort dankbar!

Grüße,
Kani

16.04.2008 - 19:33 Uhr

oder, wenn es die Startanwendung sein soll:


string pfad = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);

Grüße,
Kani

03.04.2008 - 16:22 Uhr

Hallo Mondi,

wenn ich mich nicht irre, müsste es reichen einen Verweis auf System.Windows.Forms.dll zum Projekt hinzuzufügen. Dann kannst du auch den Namespace "System.Windows.Forms" verwenden.

Oder darf man bei Diensten nicht auf System.Windows.Forms.dll verweisen?

Grüße,
Kani

25.03.2008 - 10:26 Uhr

Moin,

@herbivore: hast recht, jedes angebot hat vor- + nachteile. hätte hier nicht gleich so werten sollen!

@Khalid: die db-größe wird vom noch freien webspace abgezogen.

Grüße,
Kani

23.03.2008 - 19:37 Uhr

Hallo alpi,

ich kann von dem centron angebot nur abraten.
hatte es jetzt für ein jahr und war nicht so begeistert.
es steht einem dort keine setup-oberfläche zur verfügung und man muss den support ständig anmailen, wenn man etwas geändert haben will...

habe jetzt zu domainbox (http://www.domainbox.de) gewechselt und bin damit richtig zufrieden. man bekommt dort mehr für weniger geld... (im gegensatz zum centron-angebot)
(wurde auch hier im forum drauf aufmerksam gemacht)

Schau's dir mal an!

Grüße,
Kani

21.03.2008 - 14:57 Uhr

Hey, danke für den Hinweis!

Hab mir auch den 4gb USB-Stick geholt...

der stick hat 19,00€ gekostet + 6€ Versand... abz. 20€ gutschein macht dann 5€ für 4GB-Stick... => feine Sache so ein günstiges ostergeschenk.

Grüße,
Kani

15.03.2008 - 17:59 Uhr

Moin moin,

also @work und @home hauptsächlich C#. Für die Wartung alter Projekte @work kommt mir dann noch Gupta/Centura SQLWindows [SAL] und C++ ab und zu in die Hände.
C++ für die Dinge, die mit SAL nicht zu lösen sind ==> kann oftmals sehr viel sein 😉.

Fakt ist, C# ist seit langem meine Lieblingssprache. Aber wenn eine andere Spräche benötigt wird (warum auch immer), dann ist mir dies auch recht. => Hauptsache proggen!

Grüße und schönes Rest-WE,
Kani

15.03.2008 - 17:48 Uhr

Hallo ToxicDeluxe,

schau mal hier: FAQ Kommunkation von zwei Forms!

Grüße,
Kani

13.03.2008 - 14:59 Uhr

Also ich mache es so:


public static class Tools
{
        /// <summary>
        /// Serialisiert ein Objekt in einen Base64-Codierten String.
        /// </summary>
        /// <param name="oInput">Zu serialisierendes Objekt</param>
        /// <returns>Der Base64-Codierte String</returns>
        public static string ObjToBase64String(object oInput)
        {
            string strRet = string.Empty;

            byte[] btValue = ObjToByteArray(oInput);

            if (btValue != null)
                strRet = Convert.ToBase64String(btValue, 0, btValue.Length);

            return strRet;
        }

        /// <summary>
        /// Serialisiert ein Objekt in ein Byte-Array.
        /// </summary>
        /// <param name="oToSerialize">Objekt welches serialisiert werden soll.</param>
        /// <returns>Byte-Array mit den Objektdaten oder null bei Fehler.</returns>
        public static byte[] ObjToByteArray(object oToSerialize)
        {
            IFormatter fFormatter = new BinaryFormatter();
            byte[] btValue;
            using (MemoryStream msStream = new MemoryStream())
            {
                fFormatter.Serialize(msStream, oToSerialize);
                btValue = new byte[(int) msStream.Length];
                msStream.Position = 0;
                msStream.Read(btValue, 0, btValue.Length);
            }

            return btValue;
        }

        /// <summary>
        /// Deserialisiert ein Objekt aus einem Base64-Codierten String.
        /// </summary>
        /// <param name="strBase64">Der Base64-Codierte String mit den Objektdaten.</param>
        /// <returns>Das deserialisierte Objekt</returns>
        public static object Base64StringToObj(string strBase64)
        {
            object oRet;

            byte[] btValue = Convert.FromBase64String(strBase64);
            oRet = ByteArrayToObj(btValue);

            return oRet;
        }

        /// <summary>
        /// Deserialisiert ein Objekt aus einem Byte-Array.
        /// </summary>
        /// <param name="btValue">Byte-Array mit Objektdaten</param>
        /// <returns>Deserialisiertes Objekt oder null bei Fehler.</returns>
        public static object ByteArrayToObj(byte[] btValue)
        {
            IFormatter fFormatter = new BinaryFormatter();
            using (MemoryStream msStream = new MemoryStream(btValue, 0, btValue.Length))
            {
                msStream.Position = 0;
                return fFormatter.Deserialize(msStream);
            }
        }
}

....

// irgendwo anders
Image img = ...; // irendwo wird es schon her kommen...
string b64 = Tools.ObjToBase64String(img);
Image deserializedImage = Tools.Base64StringToObj(b64) as Image;

// jetzt nur noch deserializedImage wieder als Datei speichern...

Hoffe das hilft irgendwie...

Grüße,
Kani

// EDIT: Das ist natürlich nur ein abgespeckter (schnell rausgefriemelter) Codeausschnitt!