Sign in to follow this  

[.net] class library using internal classes

This topic is 4712 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm writing a simple C# class library engine and have a problem. The Engine class will contain public components for the end-user to directly access, for example.
//GameEngine.dll

public class Engine
{
    public CWindow Window;
    public CGraphics Graphics;
    public CTextureManager TextureManager;
}

//Game

using GameEngine;

public void Blah()
{
    Engine engine = new Engine();
    engine.Window.Blah();
    engine.Graphics.Blah();
    engine.TextureManager.Blah();
}

Is there a way to do this while having the classes hidden from the end-user? To where it was impossible for them to make their own instances, like below.
//Game

using GameEngine;

public void Blah()
{
    CWindow w;
    CGraphics g;
    CTextureManager t;
}

I've tried internal classes, but that keeps me from creating public instances of them in my engine. I would need to create wrapper methods for each class function and indirectly access them from Engine. Alternatively, if you want to share a better way to structure this, let me know.

Share this post


Link to post
Share on other sites
Perhaps you want to define the components as interfaces. Interfaces are like classes but provide no implementation; that way you give users the interface and implement the functionality internally.

Hopefully someone can give a clearer answer. Some code:


public interface IGraphics
{
void Draw(string text);
}

class GraphicsImplementation : IGraphics
{
public void Draw(string text)
{
// non-public implementation
}
}

public class Engine
{
private GraphicsImplementation _graphics = new GraphicsImplementation();

public IGraphics Graphics { get { return _graphics; } }
}

// user uses the engine
public void Main()
{
Engine engine = new Engine();
IGraphics graphics = engine.Graphics;
graphics.Draw("hello");
}

Share this post


Link to post
Share on other sites
Thanks for the help, I have a few more questions.

mutex: I admit, I haven't taken the time to learn interfaces yet. In your example, the engine user has access to IGraphics, which I am trying to avoid. I'm trying to make the engine only expose the public instances of the engine.

joanus: The compiler tells me I can't use more than one protection modifier (public internal interface IBlah) (public internal class CBlah).

ernow: I made the constructor internal and the class public, and that partially fixed my problem, but I was aiming for a "black box" engine. Where the internal classes weren't visible from the outside through the intellisense, and only the instantiated classes would be visible. For example, using the above method, the end user can see CGraphics, CTextureManager, and CWindow, but all I want visible is the public instance classes I made (Graphics, TextureManager, Window).


On a sidenote, which type of engine design do you think is better? Doing everything through the engine:


using GameEngine;

void Main()
{
//...
CEngine Engine = new CEngine(...);
SPRITE_ID = Engine.SpriteManager.LoadSprite("sprite1.spr");
Engine.Graphics.DrawSprite(SPRITE_ID);
}




or giving the engine user access to the engine sub classes:


using GameEngine;

void Main()
{
//...
CEngine Engine = new CEngine(...);
CGraphics Graphics = new CGraphics(...);
CSprite sprite1 = new CSprite("sprite1.spr");
Graphics.DrawSprite(sprite1);
}


Share this post


Link to post
Share on other sites
Quote:
Original post by Proudest
joanus: The compiler tells me I can't use more than one protection modifier (public internal interface IBlah) (public internal class CBlah).

My bad, that should be just 'internal'.

Quote:
Original post by Proudest
ernow: I made the constructor internal and the class public, and that partially fixed my problem, but I was aiming for a "black box" engine. Where the internal classes weren't visible from the outside through the intellisense, and only the instantiated classes would be visible. For example, using the above method, the end user can see CGraphics, CTextureManager, and CWindow, but all I want visible is the public instance classes I made (Graphics, TextureManager, Window).

Hold it, you want the instance visible and not the class itself? You can't, in order to use the instance the class MUST be visible to the code. However, if all you want to do is hide it from Intellisense then look up the EditorBrowsable attribute. I must ask though, why would you want to do this at all?

Quote:
Original post by Proudest
On a sidenote, which type of engine design do you think is better? Doing everything through the engine:

I'd go for door number 2. It provides for a much clearer separation between the various aspects of the engine, it provides more flexability for the end-user and it is also a more object-oriented approach (*). Conversely, the first option will make life more difficult as you have to go through the CEngine class to access anything and doesn't provide any real benefits.


* This isn't to say object-oriented is better in general, however since C# is an object-oriented language it'll more often than not be better to go with an object-oriented design.

Share this post


Link to post
Share on other sites
Quote:
Original post by joanusdmentia
Hold it, you want the instance visible and not the class itself? You can't, in order to use the instance the class MUST be visible to the code. However, if all you want to do is hide it from Intellisense then look up the EditorBrowsable attribute. I must ask though, why would you want to do this at all?


I see, I didn't know the class had to be accessible in order for the instantiated class to be accessible. Regarding EditorBrowsable, I don't want to artificially change the accessibility from it's natural form. The reason I wanted this is so the engine user had less "clutter" to deal with, and also so the engine user couldn't create his own instances of the engine's components. I wanted the engine to let the user access it's own instances, but not create his own outside the engine.

I just want to limit the user from being able to create, say, 10 CGraphics objects on his own.

Share this post


Link to post
Share on other sites
Why not have the best of both worlds (to some extent) and do something like this:

using GameEngine;

void Main()
{
//...
CEngine Engine = new CEngine(...);
CGraphics Graphics = Engine.Graphics.GetInstance();
CSprite sprite1 = Graphics.GetSprite();
Graphics.DrawSprite(sprite1);
}

Share this post


Link to post
Share on other sites
Quote:
I wanted the engine to let the user access it's own instances, but not create his own outside the engine.
Ah, then make the Graphics constructor internal. That way only code in the same assembly can call it (such as your Engine class), and it'll be inaccessible to everyone else, thus preventing users from creating their own instances of Graphics.


public class Graphics { internal Graphics() { } }

Share this post


Link to post
Share on other sites
Yep, and as for the 'clutter' use namespaces to avoid this.

eg.

// CEngine.cs
namespace MyEngineNamespace
{
class CEngine
{
public System.CWindow Window;
public System.CGraphics Graphics;
}
}


// CGraphics.cs
namespace MyEngineNamespace
{
namespace System
{
class CGraphics {...}
}
}


// CWindow.cs
namespace MyEngineNamespace
{
namespace System
{
class CWindow {...}
}
}


Share this post


Link to post
Share on other sites
Err....I fail to see how the factory pattern has anything to do with his problem. The factory pattern is for creating types at runtime without knowing the full type information, the base interface for the types (ie. IGraphics, IWindow, etc.) would still need to be public leaving him in exactly the same situation.

But yes, design patterns are generally a Good Thing.

Share this post


Link to post
Share on other sites

This topic is 4712 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this