-1

I'm trying to loop my IRepository field in my class XmlSerialization with the use of Reflection. I'm not able to define a IRepository in foreach loop instead i tried with var. But i can then not call IRepository.Save, Somehow i ned to filter the generic IRepository in the foreach loop.

The type arguments for method 'Fle.SQLServer.XmlFiles.Notifier.XmlSerialization.Save(Fle.SQLServer.Core.Services.IRepository)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

I understand my problem but cant fix it.

I want to loop my IRepository fields on XmlSerialization and call save without calling each fields in the class.

using Fle.SQLServer.Core.Model;
using Fle.SQLServer.Core.Services;

namespace Fle.SQLServer.XmlFiles.Notifier
{
  public class XmlSerialization : INotifier
  {
    private readonly IRepository<BackupDeviceLocationData> _repositoryBackupDeviceLocation;
    private readonly IRepository<BackupHistoryData> _repositoryBackupHistory;
    private readonly IRepository<DatabaseSizesData> _repositoryDatabaseSizes;
    private readonly IRepository<DiskSystemData> _repositoryDiskSystem;
    private readonly IRepository<FailedDatabaseJobsData> _repositoryFailedDatabaseJobs;
    private readonly IRepository<DatabaseReplicationData> _repositoryDatabaseReplication;
    private readonly IRepository<DatabaseLongRunningJobData> _repositoryDatabaseLongRunningJob;
    private readonly IRepository<DatabaseSystemData> _repositoryDatabaseSystem;
    private readonly IRepository<DiskBackupData> _repositoryDiskBackup;
    private readonly IRepository<SqlServerAgentEventLogData> _repositorySqlServerAgentEventLog;
    private readonly IRepository<SqlServerEventLogData> _repositorySqlEventLog;
    private readonly IRepository<DatabaseOwnerData> _repositoryDatabaseOwner;
    private readonly IRepository<RecoveryModelData> _repositoryRecoveryModel;
    private readonly IRepository<BelongToSystemData> _repositoryBelongToSystem;

    public XmlSerialization(IRepository<BackupDeviceLocationData> repositoryBackupDeviceLocation,
      IRepository<BackupHistoryData> repositoryBackupHistory,
      IRepository<DatabaseSizesData> repositoryDatabaseSizes,
      IRepository<DiskSystemData> repositoryDiskSystem,
      IRepository<FailedDatabaseJobsData> repositoryFailedDatabaseJobs,
      IRepository<DatabaseReplicationData> repositoryDatabaseReplication,
      IRepository<DatabaseLongRunningJobData> repositoryDatabaseLongRunningJob,
      IRepository<DatabaseSystemData> repositoryDatabaseSystem,
      IRepository<DiskBackupData> repositoryDiskBackup,
      IRepository<SqlServerAgentEventLogData> repositorySqlServerAgentEventLog,
      IRepository<SqlServerEventLogData> repositorySqlEventLog,
      IRepository<DatabaseOwnerData> repositoryDatabaseOwner,
      IRepository<RecoveryModelData> repositoryRecoveryModel,
      IRepository<BelongToSystemData> repositoryBelongToSystem)
    {
      _repositoryBackupDeviceLocation = repositoryBackupDeviceLocation;
      _repositoryBackupHistory = repositoryBackupHistory;
      _repositoryDatabaseSizes = repositoryDatabaseSizes;
      _repositoryDiskSystem = repositoryDiskSystem;
      _repositoryFailedDatabaseJobs = repositoryFailedDatabaseJobs;
      _repositoryDatabaseReplication = repositoryDatabaseReplication;
      _repositoryDatabaseLongRunningJob = repositoryDatabaseLongRunningJob;
      _repositoryDatabaseSystem = repositoryDatabaseSystem;
      _repositoryDiskBackup = repositoryDiskBackup;
      _repositorySqlServerAgentEventLog = repositorySqlServerAgentEventLog;
      _repositorySqlEventLog = repositorySqlEventLog;
      _repositoryDatabaseOwner = repositoryDatabaseOwner;
      _repositoryRecoveryModel = repositoryRecoveryModel;
      _repositoryBelongToSystem = repositoryBelongToSystem;
    }


    public void Notify()
    {
      foreach (var field in this.GetType().GetProperties())
      {        
        field.Save();
      }       
    }      
  }
}

3 Answers3

1

If you have a non generic repository with Save method, then you don't need reflection.

Assuming your IRepository<T> looks something like this

public interface IRepository<T>
{
    ...
    T Get(int id);
    void Save();
}

You can create a non generic repository like the following

public interface IRepository
{
    void Save();
}

And make IRepository<T> to implement it.

public interface IRepository<T> : IRepository
{
    T Get(int id);
    ...
}

If the sole purpose of XmlSerialization class is to call save, it can directly ask non generic IRepository

public class XmlSerialization : INotifier
{
    private readonly IRepository[] repositories; 
    public XmlSerialization(params IRepository[] repositories)
    {
      this.repositories= repositories;
    }

    public void Notify()
    {
       foreach (var repo in repositories)
       {        
          repo.Save();
       }       
    }      
}

No need of the dirty reflection.

If you still want to keep the XmlSerialization class fields and constructor same, you can do something like the following.

public void Notify()
{
   var repositories = new IRepository[]
       {
         _repositoryBackupDeviceLocation,
         repositoryBackupHistory,
         ...
         ...,
         _repositoryBelongToSystem
       };
   foreach (var repo in repositories)
   {        
      repo.Save();
   }       
} 
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
0

Instead of using Reflection it may be simpler to introduce a new non generic interface :

public interface IRepository
{
    void Save(); 
}
public interface IRepository<T> : IRepository
{
    // Other methods with T
}

and instead of using a lot of private fields, you can use a collection

public class XmlSerialization : INotifier
{
    private readonly IRepository[] _repositories;

    public XmlSerialization(params IRepository[] repositories)
    {
        this._repositories = repositories;
    }

    public void Notify()
    {
        foreach (IRepository repository in this._repositories)
        {
            repository.Save();
        }
    }
}

Reflection is slow and quite dirty. If your method name change, you won't have a compilation error, etc.

Cyril Durand
  • 15,834
  • 5
  • 54
  • 62
0
namespace Fle.SQLServer.XmlFiles.Notifier
{
  public class XmlSerialization<T> : INotifier
  {
    readonly IRepository<T> field;

    public XmlSerialization(IRepository<T> repository)
    {
      field = repository;
    }


    public void Notify()
    {         
      field.Save();     
    }      
  }
}
public class Registry : Autofac.Module
  {
    protected override void Load(ContainerBuilder builder)
    {
      builder.RegisterType<XmlSerialization<BackupDeviceLocationData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<BackupHistoryData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<BelongToSystemData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<DatabaseLongRunningJobData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<DatabaseOwnerData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<DatabaseReplicationData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<DatabaseSizesData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<DatabaseSystemData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<DiskBackupData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<FailedDatabaseJobsData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<RecoveryModelData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<SqlServerAgentEventLogData>>().As<INotifier>();
      builder.RegisterType<XmlSerialization<SqlServerEventLogData>>().As<INotifier>();
    }
}

As some of you told I rethink then problem and made XmlSerialization a generic class for calling IRepository.Save, then in Registry in the assembly made the registration XmlSerilaization to INotifier interface. Instead that serie of objects instead for 1 save object. But the general logic of the program handels list of INotifier with call to INotifier.Notify()