Click here to Skip to main content
15,867,765 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I have a logger class with wrapper and entries.
The type of entries varies from the case I'm using the log functions.
(Class for imports, exports, statistics, etc.)

Is there a way to set the type in List<t> by a parameter in the constructor?

What I have tried:

public abstract class EntryBase() { 
    public DateTime Timestamp { get; set; } = DateTime.Now;
    public string UserInfo { get; set; } = "";
}

// Concrete classes
// notice: Export/ImportFilename are examples and can't change to Filename...
public partial class ExportEntry : EntryBase {
   public string ExportFilename { get; set; } = "";
}

public partial class ImportEntry : EntryBase {
   public string ImportFilename { get; set; } = "";
}

public partial class StatisticEntry : EntryBase {
   public DataSet Summary { get; set; } = new DataSet();
}

public class Log {
  var entries = new List<EntryBase>();

  //constructor with concrete type parameter
  Log(EntryBase concreteEntryType) {
      entries = new List<concreteEntryType.GetType()>();
  }

  DoSomeLogFunctions() {
     //...
  }
}

public void Main() {
  var import = new Log(ImportEntry);
  var export = new Log(ExportEntry);
  var statistic = new Log(StatisticEntry);
}
Posted
Updated 9-Apr-18 0:39am
v3

0) I would like to point out that you have an abstract class without any virtual methods or properties to override.

1) I would combine Import and Export objects into a single object with an enum that indicates which direction (import/export) is applicable to the object.

2) I would define Log as follows
C#
public class Log : List<EntryBase>
{
}

and then add methods that would do all the heavy lifting where type determination/handling is concerned.
 
Share this answer
 
Comments
Sni.DelWoods 3-Apr-18 5:41am    
That's the definition I was looking for:
public class Log : List<entrybase> {}

The code was not complete and just an example.
By writing the question I figured out it's a better way for me to use the Log as base class:

public abstract class LogBase() {}
public class ImportLog : LogBase() {
var entries = new list<importentry>();
//...
}

Thank you anyway for the solution.
If i understand you correctly, a Log class has to be a generic class[^], which gets as an input a class derived from EntryBase class. It 's called constraints. See: Constraints on Type Parameters (C# Programming Guide) | Microsoft Docs[^]

Seems, your Log class have to behave as a List<t>[^] generic class:
C#
public void Main() {
  var import = new List<ImportEntry>();
  var export = new List<ExportEntry>();
  var statistic = new List<StatisticEntry>();
}
 
Share this answer
 
Thanks for the comments.
I've found my working solution:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;

public abstract class LogBase
{
    public class EntryBase
    {
        public DateTime Timestamp { get; set; } = DateTime.Now;
        public string Title { get; set; } = "";
    }

    public List<EntryBase> entries = new List<EntryBase>();
}

public class LogGeneral:LogBase
{
    // General-Log derrived from unchanged LogBase
}

public class LogImport : LogBase
{
    public class ImportEntry : EntryBase
    {
        public string Filename { get; set; } = "";
    }

    new public List<ImportEntry> entries = new List<ImportEntry>();
    public string ImportDetail { get; set; } = "";
}

public class LogStatistic : LogBase
{
    public class ImportEntry : EntryBase
    {
        public DateTime dateStart { get; set; } = new DateTime(1900, 1, 1);
        public DateTime dateEnd { get; set; } = new DateTime(9999, 12, 31);
    }

    new public List<ImportEntry> entries = new List<ImportEntry>();
    public DataSet StatisticData { get; set; } = new DataSet("statistic");

    public string HtmlReport()
    {
        return "<html><body>" + StatisticData.DataSetName + "</body></html>";
    }
}

public static class LogHelper
{
    public static void WriteLog(ICollection entries, string fsPath)
    { /* serialize entries to csv-Data and save to file */ }

    public static void WriteLog(string content, string fsPath)
    { /* save data to file */ }
}

public static class TestTheLog
{
    public static void Do()
    {
        var logGeneral = new LogGeneral();
        LogHelper.WriteLog(logGeneral.entries, @"d:\log1.csv");

        var logImport = new LogImport();
        if (logImport.ImportDetail == "ok") { LogHelper.WriteLog(logImport.entries, @"d:\log2.csv"); }

        var logStatistic = new LogStatistic();
        LogHelper.WriteLog(logStatistic.HtmlReport(), @"d:\log3.htm");
        LogHelper.WriteLog(logStatistic.entries, @"d:\log3.csv");
    }
}
 
Share this answer
 
Comments
Sni.DelWoods 4-Apr-18 7:04am    
...just to finish the Code..
Using the Log in a generic class (class Import, class Statistic...):

public void Test()
{
    var managerGeneral = new Manager<LogGeneral>();
    // Manager can do the work which has to be logged in the specific log type.
}

public class Manager<T> where T:LogBase   
{        
    public T Log = (T)Activator.CreateInstance(typeof(T));    
}
The method
FillDerrivedFromBase(object classDerrived, object classBase)
copies all values of a base class to the derrived class. This works also fine with List<derrivedclass> and I don't have to worry about the types.

Simple way to fill the derrived instance with the data of the base instance:

public static class BaseDerrivedCopy
  {

      public static void DoTest()
      {
          var e0 = new LogBase.EntryBase();
          e0.Title = "test";

          //e0.Timestamp: 2018-04-09 00:00:00
          //e0.Title: "test"

          System.Threading.Thread.Sleep(200); //Wait 2sec to get a different timestamp

          var e1 = new LogImport.EntryImport();
          e1.Filename = "file1.txt";
          //e1.Filename: file1.txt
          //e1.Timestamp: 2018-04-09 00:00:20
          //e1.Title: ""

          FillDerrivedFromBase(e1, e0);
          //e1.Filename: file1.txt
          //e1.Timestamp: 2018-04-09 00:00:00
          //e1.Title: "test"
      }

      /// <summary>
      /// Copies the values of a base class instance to the given derrived class instance
      /// </summary>
      /// <param name="classDerrived">Instance of derrived class</param>
      /// <param name="classBase">Instance of base class</param>
      public static void FillDerrivedFromBase(object classDerrived, object classBase)
      {
          foreach (var prodSrc in classBase.GetType().GetProperties())
          {
              classDerrived.GetType().GetProperty(prodSrc.Name).SetValue(classDerrived, prodSrc.GetValue(classBase));
          }
      }

      public class EntryBase
      {
          public DateTime Timestamp { get; set; } = DateTime.Now;
          public string Title { get; set; } = "";
      }

      public class EntryImport : EntryBase
      {
          public string Filename { get; set; }
      }
  }
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900