2
\$\begingroup\$

I would like to implement service with explicit interface implementation. I don't want to have public methods in service, only possible way to create instance is trough interface.

I am not sure what is best way to call method of same class if method is explicit implementation of interface method.

You can see in my code that I am using "AsIArchiveService" property.

I have public interface in class library:

using Common.Entities;
using System.Threading.Tasks;

namespace Common.Services
{
    public interface IArchiveService
    {
        Task<ArchiveConfiguration> GetConfiguration();

        Task<bool> Update(ArchiveConfiguration machine);
    }
}

Serivice class in main project:

using Common.Configurations;
using Common.Entities;
using Common.Services;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using RemoteManager.EntityFramework;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Manager.Services
{
    internal class ArchiveService : IArchiveService
    {
        private readonly IOptions<ApplicationConfiguration> applicationConfiguration;
        private readonly ILogger<ArchiveService> logger;
        private readonly ManagerContext context;
        IArchiveService AsIArchiveService
        {
            get { return this; }
        }

        internal ArchiveService(ManagerContext context, IOptions<ApplicationConfiguration> applicationConfiguration, ILogger<ArchiveService> logger)
        {
            this.applicationConfiguration = applicationConfiguration;
            this.logger = logger;
            this.context = context;
        }

        async Task<ArchiveConfiguration> IArchiveService.GetConfiguration()
        {
            try
            {
                logger.LogInformation($"Start  {nameof(ArchiveService)}:{nameof(AsIArchiveService.GetConfiguration)}");
                if (this.context.ArchiveConfiguration.Count() == 0)
                {
                    var res = this.context.ArchiveConfiguration.Add(new ArchiveConfiguration() { isArchive = true, maxDataSetCount = 20, path = Path.Combine("C:/", "TestArchive") });
                    this.context.SaveChanges();
                }
                var result = this.context.ArchiveConfiguration.First();
                return await Task.FromResult(result);
            }
            catch
            {
                logger.LogError($"Error {nameof(ArchiveService)}:{nameof(AsIArchiveService.GetConfiguration)}");
                throw;
            }
        }

        async Task<bool> IArchiveService.Update(ArchiveConfiguration archive)
        {
            try
            {
                logger.LogInformation($"Start {nameof(ArchiveService)}:{nameof(AsIArchiveService.Update)}");
                this.context.Entry(archive).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                this.context.SaveChanges();
                return await Task.FromResult(true);
            }
            catch
            {
                logger.LogError($"Error {nameof(ArchiveService)}:{nameof(AsIArchiveService.Update)}");
                throw;
            }
        }
    }
}
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Why does the interface implementation need to be explicit? \$\endgroup\$ Commented Dec 5, 2016 at 15:33
  • \$\begingroup\$ Why do you need the property? IArchiveService service = new ArchiveService(); gives you an IArchiveService. I'm not sure why you'd need the property to return itself as its interface? \$\endgroup\$
    – Ron Beyer
    Commented Dec 5, 2016 at 15:35
  • \$\begingroup\$ I am using Dependency injection, so IArchiveService will be resolved from container. I don't want to have public methods in class, that is why I want explicit interface implementation, it just looks to me like better solution in my case. It does not have to be explicit, but I think that this is good example when should be, because that is way how I plan to use all service classes - only with dependency injection resolver. Main reason why I post this question is because I am not sure if this is best approach. \$\endgroup\$ Commented Dec 6, 2016 at 7:27

2 Answers 2

3
\$\begingroup\$

You're only using AsIArchiveService to statically get the name of the current method. Instead, you could go off the interface directly, nameof(IArchiveService.GetConfiguration), which obviously returns the same value as going through AsIArchiveService.GetConfiguration.

logger.LogInformation($"Start  {nameof(ArchiveService)}:{nameof(IArchiveService.GetConfiguration)}");

If you changed your four usages in your log lines to go this route, you could dispense with the peculiar property you created altogether.

\$\endgroup\$
2
\$\begingroup\$

I would like to implement service with explicit interface implementation. I don't want to have public methods in service, only possible way to create instance is trough interface.

This is not true and it won't work like that. Interface is a public API. All interface members are public by default and cannot be changed. You can always cast a type into an interface it implements and use its methods.

There's not point explicitly implementing an interface here. We do this only if there's a name conflict between two interfaces having the same method like IEnumerable and IEnumerable<T> which both define the GetEnumerator().


I am not sure what is best way to call method of same class if method is explicit implementation of interface method.

This is an off-topic question for CR but I'll answer it this time: you need to cast:

((IYourInterface)this).SomeMethod();

Assuming SomeMethod is implemented explicitly.


I am using Dependency injection, so IArchiveService will be resolved from container. I don't want to have public methods in class, that is why I want explicit interface implementation, it just looks to me like better solution in my case.

But you do. How are you going to use it if it does not provide any methods?

[...] but I think that this is good example when should be, because that is way how I plan to use all service classes - only with dependency injection resolver. Main reason why I post this question is because I am not sure if this is best approach.

This approach would work but it is not necessary at all. DI will pass an instance of ArchiveService that implements IArchiveService as IArchiveService. It makes no difference for the user if it's been implemented implicitly or explicitly as he will only see what the IArchiveService provides.

I think you need some reading about interfaces:

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.