How to define 'public' and 'private' interfaces to an object?
I have a database and a DAL class that manages object-to-data (and vice-versa) mapping, in a similar way to Entity Frameworks - but we can't use EF here yet, so the DAL is a quite simple home-grown library that exposes a few objects and allows actions to be performed on them. It works, and will do until we can go to a 'proper' EF solution.
The DAL offers a variety of objects to 'client' applications, with methods and properties defined to encapsulate the logic of each action and hide the internal state of those objects as well as the mechanics needed to persist them to the database. This works too.
However, there are some actions that are exposed by the DALs' object interfaces which should really be 'private' - they are used by a service application that runs elsewhere, doing various background stuff to the objects in the da开发者_运维知识库tabase. I do not really want the 'client' applications to be able to see these methods, but I do want the methods to be visible when the DAL is referenced by the service application.
Example of the current implementation:
DAL Library Object Method LoadObject() Method SaveObject() Method AdjustInternalObjectProperty()
Thus, the client apps can see all three methods, though they should never use the third - that is a function that should only be visible to the service app (which should be able to see and use all three methods).
So the question is, what is the best approach to take which will preserve the intention of using interfaces to each object, but which will 'hide' parts of that interface and only make the hidden parts accessible to a suitably 'friendly' service app. Is there some access modifier technique that will let me make certain parts of the interface 'private', with a mechanism that the service app uses (but the client does not) to gain access to those private elements? Or is this a scenario where two different interfaces should exist, where the 'client' interface simply omits the 'internal' methods? Or something else?
I want to do this the 'right' way - I've searched SO and found a bunch of answered questions regarding multiple object interfaces, but none seem to quite hit the spot for my specific question. If there is an existing answer, by all means point me at it and close this question.
EDIT (after reading answers and experimenting):
using System;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Test")]
namespace Interface_Test
{
public interface IStandard
{
void StandardMethod();
}
internal interface ISuper : IStandard
{
void SuperMethod();
}
public sealed class TestClass : ISuper
{
public void StandardMethod()
{
Console.WriteLine("The standard method");
}
void ISuper.SuperMethod()
{
Console.WriteLine("The super method");
}
}
}
This does the job - the bulk of the object exposure is through the IStandard
interface, which is a bog-standard public interface that any and all client assemblies can use. The 'restricted' stuff is only accessible through the alternate ISuper
interface, which inherits all the core stuff from IStandard
but adds the extra items that I only want a specific 'service client' to use. By adding the [InternalsVisibleTo]
attribute as suggested, this interface and its' methods/properties are completely invisible to all but the named assembly.
The downside is that there are two interfaces, but in the absence of a language facility such as allowing 'internal'
as a modifier on interface method definitions it's a reasonable way of ensuring client assemblies can't get to features the interface supports but which aren't for general use.
One option is:
- Create an
internal
interface - Implement it explicitly (to avoid requiring public methods)
- Use
[InternalsVisibleTo]
to give your "service application" access to the internal interface
You may be interested in this blog post which shows a few interesting options for other situations.
One common approach is to have 2 interfaces:
public interface IBar
{
void DoSimpleStudd();
int This {get;}
}
public interface ISuperBar : IBar
{
void DoComplexStuff();
int That {get; set;}
}
// at service layer
public class ServiceWidget
{
public ISuperBar Bar {get; set;}
...
}
// other places
public class ServiceWidget
{
public IBar Bar {get; set;}
...
}
So in the service layer
, they will be using ISuperBar
and in other parts of the application, they will use IBar
.
UPDATE
Yes, interfaces are meant to be public.
精彩评论