Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
343 views
in Technique[技术] by (71.8m points)

c# - Does MEF lend any value to the Singleton pattern?

I am working on an MEF project to discover usage and implementation techniques. My first phase of discovery is to implement a dynamically configurable and centralized data controller. One way to customize behavior is to inherit a class I provide that enforces a singularity rule. While the Singleton pattern is much maligned in it's use, I may have found an implementation that could validate, to some degree, the pattern's struggling existence.

The Situation

Suppose a data control module (DataController) imported by the Host is intended to supply a common conduit to databases on request by sibling modules. I only need one DataController and to be composed as a module, DataController must implement IDataController. Implementation of DataProvider as the base class is purely optional; however, derivation from DataProvider will require some additional handling.

The Observations

Gathering the facts:

  • A static class cannot implement or extend abstract classes or interfaces. This fact alone eliminates the use of a static class to ensure a singular existence of a DataController.

  • A DataController implementing the Singleton pattern would ensure a singular existence per application domain. There is no restriction on the DataController; allowed to inherit the required interface to be imported and composed in the Host.

  • Given derivation of DataController, the standard implementation for the Singleton pattern may prove to be challenging in same cases. The proposed data library provides both publicly accessible classes: IDataController, and an abstract DataProvider. To ensure a single instance of the derived DataController, the implementation will require some deviation from the norm.

The Solution

At this point, the solution seems clear. Implementation of the Singleton pattern by the DataHandler base class. I am not naive enough to think that there are other ways I could do this. But here is my rough expectations on how to implement the pattern:

// DataLibrary referenced by Host
public interface IDataController
{ 
    IDataController Start();
    DbConnection CreateConnection<TDbConnection>(params string[] args)
        where TDbConnection : DbConnection, IDbConnection;
}

public abstract class DataProvider
{

    // singleton implementation
    private static IDataController dcInstance;

    protected static IDataController Instance
    {
        get{ return dcInstance; }
    }
    // ========================

    abstract IDataController CreateController();

    protected IDataController instanceController<TDataController>()
        where TDataController : IDataController, new()
    {
        return new TDataController ();
    }
}

// references DataLibrary
[Export(typeof(IDataController))]
public class DataController : DataProvider, IDataController
{
    public IDataController Start()
    {
         return CreateController();
    }

    protected override IDataController CreateController()
    {
        return instanceController<DataController>();
    }

    public SqlConnection CreateConnection(params string[] args)
    {
        // instance and return new SqlConnection 
    }
}

Keep in mind that I have been working this out - read, theorizing - and have not completed the implementation. There will most likely be some updates as I debug any issues.

Obviously, this implementation is only enforced if the DataController module inherits the abstract base class, DataProvider. Therefore, it stands to reason that we should enforce a rule of singularity to avoid abuse or misuse if the developer opts to derive a DataController from DataProvider.

All that said, I am curious if there is a more acceptable, or practical implementation than what I have devised. And, I begin to question if the Singleton pattern is the right choice. With the Singleton pattern's much maligned existence (and, for the most part, rightfully so), I should, therefore, question my choice.

Is there a more practical implementation to meet my requirements? *Is this the right implementation of the Singleton pattern in this case?* Does this implementation actually lend any value to the pattern's existence?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you want to enforce the fact that only a single instance of a class exists in the container, then you can just set the "shared" part creation policy:

[Export(typeof(IDataController))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class DataController : IDataController
{
    ...
}

Each part importing IDataController will then receive the same instance. Note that this already the default behavior in MEF if you specify no part creation policy at the import or export side.

You should not build "singletonness" into a class. Whether something is a singleton is part of the component metadata or the configuration of the container. Other dependency injection containers follow the same approach. For example, in autofac you declare something as being a singleton like this:

builder.Register(c => new DataController())
    .As<IDataController>().SingleInstance();

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...