Sni.DelWoods Ответов: 4

Регистратор класса, которые можно вывести классы и различные записи (изменено с: создать экземпляр список<Т> по параметру)


У меня есть класс logger с оболочкой и записями.
Тип записей зависит от случая, когда я использую функции журнала.
(Класс для импорта, экспорта, статистики и т. д.)

Есть ли способ задать тип в списке<t> с помощью параметра в конструкторе?

Что я уже пробовал:

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);
}

4 Ответов

Рейтинг:
20

Sni.DelWoods

Спасибо за комментарии.
Я нашел свое рабочее решение:

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");
    }
}


Sni.DelWoods

..- просто чтобы закончить код..
Использование журнала в универсальном классе (импорт класса, статистика класса...):

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));    
}

Рейтинг:
2

Maciej Los

Если я правильно вас понял, а Log класс должен быть а универсальный класс[^], который получает в качестве входных данных класс, производный от EntryBase класс. Это называется ограничениями. Видеть: Ограничения на параметры типа (руководство по программированию на C#) | Microsoft Docs[^]

Кажется, ваш Log класс должен вести себя как Список<t>[^] универсальный класс:

public void Main() {
  var import = new List<ImportEntry>();
  var export = new List<ExportEntry>();
  var statistic = new List<StatisticEntry>();
}


Рейтинг:
10

Sni.DelWoods

Метод

FillDerrivedFromBase(object classDerrived, object classBase)
копирует все значения базового класса в класс derrived. Это также прекрасно работает с List<derrivedclass>, и мне не нужно беспокоиться о типах.

Простой способ заполнить дерривированный экземпляр данными базового экземпляра:

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; }
      }
  }


Рейтинг:
1

#realJSOP

0) я хотел бы отметить, что у вас есть абстрактный класс без каких-либо виртуальных методов или свойств для переопределения.

1) я бы объединил объекты импорта и экспорта в один объект с перечислением, которое указывает, какое направление (импорт/экспорт) применимо к объекту.

2) я бы определил Log следующим образом

public class Log : List<EntryBase>
{
}

а затем добавьте методы, которые будут выполнять всю тяжелую работу, связанную с определением типа/обработкой.


Sni.DelWoods

Именно это определение я и искал:
публичный журнал классов : List<entrybase> {}

Код был неполным и просто примером.
Написав этот вопрос я понял что это лучший способ для меня использовать журнал в качестве базового класса:

публичный абстрактный класс LogBase() {}
открытый класс ImportLog : LogBase() {
var entries = новый список<importentry>();
//...
}

В любом случае спасибо вам за решение.