Click here to Skip to main content
15,892,161 members
Please Sign up or sign in to vote.
4.00/5 (3 votes)
See more:
Basically, I'm using an interface to pass objects which use that interface to a method. (Yeah, I'll explain with code.)

I've created a service manager class, it looks like this.

C#
public static class ServiceManager
{
    // Services
    private static Dictionary<Type, object> Services = new Dictionary<Type, object>();

    // Add Service (This is the working version thanks to the solution provided.)
    public static void AddService(object obj)
    {
        AddService(obj.GetType(), obj);
    }

    // Get Service
    public static T GetService<T>()
    {
        return (T)Services[typeof(T)];
    }
}


I'm passing my object to the following method using my interface rather than my class type. (This is part of my ComponentManager class.)

C#
public void Add(IGameComponent component)
{
    Components.Add(component);
    component.Initialize();
}


I want to add the actual class type to my service manager in that method, like this..

C#
public void Add(IGameComponent component)
{
    Type t = component.GetType();
    ServiceManager.AddService<t>(component);
    Components.Add(component);
    component.Initialize();
}


I've tried about every variation I can think of, typeof, GetType, I even looked into using System.Reflection, but couldn't figure it out. (So, in short, I need to cast component back to it's base type, for use as T in my AddService call.)

I hope I've explained this adequately. (And sorry about posting another question so soon.)

---

I just want to add, I've checked the results of Type t, and it does indeed get my class, however, AddService refuses to accept it as a parameter. (Is this a bug, or is there a special method needed in this case?)
Posted
Updated 10-Jan-12 23:02pm
v4

All wrong. You need to understand a number of very fundamental and pretty simple things.

Interface are real types. You need to understand that there are compile-time types and run-time types. Interfaces can be only compile-time types because there one cannot create an object of interface type. Nevertheless, interface reference can represent an real object, only the run-time type of this object can be some structure or class implementing the interface. There is no such thing as "interface to a method". Type casting is a bad thing and can be avoided in most cases. And finally, you should not "try about every variation you can think of". If you try couple of things and failed, you already are doing something wrong. You need to understand things, not to get some result which "just works". It something "just works", it does not really work if you don't understand how.

Basically, this is pretty much all what you need to understand at this time, but you need to understand it well.

Now, you add only the components of the type IGameComponent. So, you need to following method:

C#
public static class ServiceManager {
    // Services
    private static Dictionary<Type, object> Services = new Dictionary<Type, object>();

    // Add Service
    public static void AddService<T>(IGameComponent obj)
    {
        Services.Add(typeof(T), obj);
    }
}


Now, I don't know the purpose of the type in your dictionary. Chances are, you need a run-time type, so it should be even simpler:



C#
public static class ServiceManager {
    // Services
    private static Dictionary<Type, object> Services = new Dictionary<Type, object>();

    // Add Service
    public static void AddService(IGameComponent obj)
    {
        Services.Add(obj.GetType(), obj);
    }
}


—SA
 
Share this answer
 
Comments
[no name] 11-Jan-12 4:19am    
All wrong.

Interfaces in this case are a delegate type to the real type.

My class inherits the interface, allowing me to pass it as a parameter under that interface type. (Like an alias.)

Simply using component.GetType().ToString() shows me the real type, however, the generic parameter won't accept it, so perhaps a dynamic(the keyword) object, or something, "var", etc, could help accomplish this.

If not, surely, Reflection can, it is runtime, not compile time, after all.

In any case, I disagree.

---

For the record, I marked the solution I did, because it works, it works because it uses GetType(), which I mentioned trying. (GetType is as far as I know a function of Reflection.)

---

In explanation, nothing was all wrong, I simply tried to pass the type in incorrectly, and when it failed, I tried various other methods.

(So, correct or not, I didn't like the way you phrased your answer. Hence the no vote, etc,.. Sorry, a bit drunk, so my responses are a bit disjointed, and I won't edit the post, on principle, hah.)

(Edit: This seems more like the compiler being picky, my original attempt, and the solution are equivalent, I resolved obj to Type just like it does, it just didn't recognize the value inside a variable.)
Sergey Alexandrovich Kryukov 11-Jan-12 13:18pm    
Interfaces? delegate? "To real type"?
I got it -- you don't need any help! You are on your own now.
--SA
[no name] 11-Jan-12 18:58pm    
You have no idea what you're talking about.

Interfaces, are indeed a "real" type, however, they are NOT the real type of the object I was passing. (Which is what this question pertained to.)

Yes, delegate, this is not only a type in C#, but, a word in English, here is an excerpt from the dictionary.

"to commit (powers, functions, etc.) to another as an agent or deputy. "

Sounds about right.

Take your bad advice, attitude, and lack of programming\English knowledge down the road.
If the key in your Dictionary should always be the concrete type of the object than you don't need the generic parameter:
C#
// Add Service
public static void AddService(object obj)
{
    Services.Add(obj.GetType(), obj);
}

If the key is "sometimes" different from the actual object than you should convert the generic parameter into a normal parameter:
C#
public static void AddService(Type t, object obj)
{
    Services.Add(t, obj);
}

The base problem your are facing with your solution is that you want to determine and use a type identified in runtime, but generics are compile time magic.

Thinking about it you should probably overload your function:
C#
public static void AddService<t>(object obj)
{
    AddService(typeof(T), obj);
}
public static void AddService(object obj)
{
    AddService(obj.GetType(), obj);
}
public static void AddService(Type t, object obj)
{
    Services.Add(t, obj);
}</t>

Now you have everything :).
 
Share this answer
 
Comments
[no name] 11-Jan-12 4:12am    
I haven't tested this yet, but the changes look good, thank you, I should have thought of using a concrete type as you suggested, can't believe I missed that. :)

Edit:

I just tried it out, it seems to be working, thanks a lot, I knew there had to be a simple method to accomplish this. :)
An interesting question, which I've voted-up out of curiosity.

And, I'll respond to it "in depth" because what you are dealing with here indirectly relates to some experiments I am doing with using interfaces: so it's inherently of value to me to try and implement a test case based on your ideas.

These comments (too long for just a standard thread comment, and they include code which I want displayed formatted) are offered here not because I believe I have a "solution" for your design scenario (I don't pretend to understand it fully), but with the hope they may, at least, contribute to clarification of the question asked, or be of some benefit to other CP members.

One thing that immediately comes to mind: is that since you are using a Type object as the key to a Dictionary: that means one-and-only-one Type is going be able to be added to the Dictionary (you'll get a duplicate key error if you add more than one of any Type).

If there's one-and-only-one instance of each Type: why use a Dictionary here ?

Which raises a secondary question, for me: since you want one Dictionary entry per instance of object (you are now passing in the objects' instances for the 'Value argument in the Dictionary): don't you want to use a Dictionary<obj<T>, Type>) ?

In which case 'AddService now might look like:
public static void AddService<T>(T obj)
{
    Services.Add(obj, typeof(T));
}
I did create a simple test example using this approach in which I verified that it would compile, using this for a test interface:
CSS
// must include these references to use this interface:
using System.Windows.Forms;
using System.Drawing;
//
public interface IWhatEver
{
    Size bSize { get; set;}
    Point bLoc { get; set; }
}
Then, I could make a calls like this;
C#
// the argument 'theMButton passed in here
// is an instance of a class that inherits from both Button and IWhatEver
private void AddModButton(IWhatEver theMButton)
{
    ServiceManager.AddService(theMButton);
}
Prior to testing, I added a method to the ServiceManager class, to expose the Services Dictionary:
C#
public static Dictionary<object, Type> GetServices()
{
    return Services;
}
The code I used to test this little sandbox experiment was
ServiceManager.AddService(new Button());
ServiceManager.AddService(new ModButton(bName: "inherited Button"));
ServiceManager.AddService(new TextBox());
ServiceManager.AddService(new ListBox());

ModButton mb2 = new ModButton(bName: "second inherited Button");
AddModButton(mb2 as IWhatEver);

IWhatEver mb3 = new ModButton(bName: "third inherited Button");
AddModButton(mb3);
Then, I examined the contents of the Services Dictionary like this:
C#
private void InspectServices()
{
    Console.WriteLine();

    foreach (var theKVP in ServiceManager.GetServices())
    {
        Console.WriteLine("object = " 
          + theKVP.Key.ToString() 
          + " : type = " 
          + theKVP.Value.ToString());

        if (theKVP.Value.BaseType != null)
        {
            Console.WriteLine("base class = " 
              + theKVP.Value.BaseType.ToString());
        }
        else if (theKVP.Key is IWhatEver)
        {
            Console.WriteLine("This is an IWhatEver interface");
            Console.WriteLine("This IWhatEver cast back to Button is : "
              + (theKVP.Key as Button).ToString() 
              + " : Name = " 
              + (theKVP.Key as Button).Name);
        }

        Console.WriteLine();
    }
}
 
Share this answer
 
v2
Comments
[no name] 11-Jan-12 4:03am    
The ServiceManager simply holds important services, like for example, my InputManager, it allows me easy global access to it, but let's me keep it an instantiable type. (As compared to having a static class.)

I have to call dispose on the DirectInput object I've created in this class(InputManager) to gather input.

(This is similar to how XNA handles it's services, if I'm not mistaken, or perhaps the content pipeline? At any rate, I based it on a technique used by XNA.)

---

Edit:

I access it like this.

InputManager input = new InputManager();
ServiceManager.AddService(input);
ServiceManager.GetService T ().Method(); // Or I can assign it to a temporary ref if I need to access it a lot.

You can also use it as the private value of a property within a class where you might want input. (Just to offer a nice user interface, in my case, I might do this in my Game class, so I can directly access it.)

ex: this.Input.KeyUp(Key.Escape)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900