0

Let's say I have an object class (widgetBlue). This object class fulfills an interface (iWidgetBlue) and inherits from an abstract class (widget). widgetBlue does NOT have an explicitly coded constructor and has information needed to perform actions against it.

I want to be able to create an instance of widgetBlue in WidgetService to be returned to the consumer so that they can work with it but not allow the consumer to create an instance of widgetBlue out of the blue. WidgetService needs to be able to create a new widgetBlue and instantiate its properties.

So this would be okay:

WidgetBlue retVal = SomeRemoteMethodThatReturnsAWidgetBlue();

But this would not be okay:

WidgetBlue retVal = new WidgetBlue();

Edit: Furthermore, the widget objects are all in their own project and referenced by both the consumer and the service.

How would I do this?

user4593252
  • 3,496
  • 6
  • 29
  • 55

4 Answers4

2

If I'm understanding your question correctly, you could just create a parameter-less constructor in WidgetBlue and set it to have an internal access modifier. That way, you could only create new instances from classes within the same assembly (e.g. your WidgetService class) and not from your consumer which I'm assuming is an external assembly.

rory.ap
  • 34,009
  • 10
  • 83
  • 174
  • Correction: there is no constructor. Sorry. I've editted my question to reflect that. – user4593252 Mar 17 '16 at 19:31
  • Just create a parameter-less constructor then with an `internal` access modifier. See my updates... – rory.ap Mar 17 '16 at 19:33
  • Hrm, the widget class I want to protect is in it's own project and namespace, referenced by the remote method and would be referenced by the consumer. Makes it easier to maintain code. This has the desired effect except I can't instantiate it in the remote service that would return the object. – user4593252 Mar 17 '16 at 19:38
  • You could probably use reflection then. Read this (or google it on your own): http://stackoverflow.com/questions/708952/how-to-instantiate-an-object-with-a-private-constructor-in-c – rory.ap Mar 17 '16 at 19:40
  • That seems like magic. What's to stop someone from using the same trick you linked to? – user4593252 Mar 17 '16 at 19:51
  • 1
    There's nothing to stop someone from doing that. Just like there's nothing to stop someone from reverse-engineering your code to see how your magic works, and in fact that's how the tools like IL Spy and Redgate's .NET Reflector do it -- using reflection. Just don't ever hide any secrets in your code, like encryption/decryption keys :) – rory.ap Mar 17 '16 at 19:55
2

I usually accomplish stuff like this by hiding the concrete class in some other assembly. Make WidgetBlue an internal class, then you can supply instances of it from a WidgetFactory that creates IWidgets (you can have a BuildBlue() method and you can easily extend it to provide red ones as well later if you want). This completely decouples clients from your concrete implementation. It's called the interface segregation principle.

namespace Widgets
{
    public interface IWidget
    {
    }

    internal abstract class Widget : IWidget
    {
    }

    internal class BlueWidget : Widget
    {
    }

    public class WidgetFactory
    {
        public IWidget BuildBlue()
        {
            return new BlueWidget();
        }
    }
}

In some other project:

using Widgets;

namespace Client
{
    public class Client
    {
        public static void Main(string[] args)
        {
            IWidget blueWidget = new WidgetFactory().BuildBlue();
            IWidget otherBlueWidget = new BlueWidget(); // doesn't compile
        }
    }
}
sara
  • 3,521
  • 14
  • 34
  • I really like this. I'm about to test the other answer I choose. if it doesn't work, I'm going to use this one. It looks a lot like a factory pattern? – user4593252 Mar 17 '16 at 20:05
  • yes, this is one of the factory patterns, pretty simple, but still handy. I use it in production code all the time. – sara Mar 18 '16 at 07:58
0

A better approach is to use Interfaces so the concrete class is abstracted from the consumer and even hidden if you mark the concrete class as internal. An interface is a contract so there is no concept of an instance of an interface / ie. interface constructor.

Your example would then be.

internal class WidgetBlue : IWidgetBlue {}

IWidgetBlue retVal = SomeRemoteMethodThatReturnsAIWidgetBlue();

And this is not possible

IWidgetBlue retVal = new IWidgetBlue();

It also allows you to change the underlying implementation in the future or extend it as you see fit.

Igor
  • 60,821
  • 10
  • 100
  • 175
0

You could do it with the builder pattern:

public Builder
{
    bool _prop = false;
    public Builder WithProperty(bool prop)
    {
        _prop = prop; 
         return this;
    }
    public Widget Build(){ 
        if(prop)
           return new FooWidget();
        else 
           return new BarWidget();
    }   
}

public abstract class Widget()
{
}

public class FooWidget: Widget{}
public class BarWidget: Widget{}

You cannot instantiate the abstract Widget, and you hide the actual choice of higher implementation behind an abstraction.

Meirion Hughes
  • 24,994
  • 12
  • 71
  • 122