2017-04-21 8 views
6

Ich habe einen einfachen Service-Manager namens ServiceManager, die zwei Methoden hat. Create() erstellt eine Instanz eines Dienstes. Provide() gibt einen Dienst zurück, der zuvor erstellt wurde.Get-Instanz aus einem Wörterbuch von Typen und Instanzen

Ich habe eine grundlegende Implementierung, die funktioniert, aber ich frage mich, ob es einen saubereren Weg gibt. Dies ist meine grundlegende Umsetzung des ServiceManager:

public class ServiceManager : MonoBehaviour 
{ 
    private Dictionary<Type, MonoBehaviour> services = new Dictionary<Type, MonoBehaviour>(); 

    public void Create<T>() where T : MonoBehaviour 
    { 
     // Create service 
     GameObject serviceObject = new GameObject(typeof(T).Name); 
     serviceObject.transform.SetParent(transform); // make service GO our child 
     T service = serviceObject.AddComponent<T>(); // attach service to GO 

     // Register service 
     services.Add(typeof(T), service); 
    } 

    public T Provide<T>() where T : MonoBehaviour 
    { 
     return (T)services[typeof(T)]; // notice the cast to T here 
    } 
} 

Mit dem Service ist einfach:

public class ServiceTest : MonoBehaviour 
{ 
    private void Start() 
    { 
     // Creating services 
     ServiceManager services = FindObjectOfType<ServiceManager>(); 
     services.Create<MapService>(); 
     services.Create<InteractionService>(); 
    } 

    private void Example() 
    { 
     // Get a service 
     ServiceManager services = FindObjectOfType<ServiceManager>(); 
     MapService map = services.Provide<MapService>(); 
     // do whatever you want with map 
    } 
} 

Meine Frage ist über ServiceManager.Provide(). Beachten Sie die Umwandlung in T, nachdem Sie das Element aus dem Wörterbuch abgerufen haben. Das fühlt sich sehr unrein an und lässt mich darüber nachdenken, ob etwas daran fehlt, wie Generika in C# funktionieren. Gibt es andere/bessere Möglichkeiten, um das zu erreichen, was ich erreichen möchte?

+1

* "Dieses Gefühl sehr unsauber" * - nicht zu mir es nicht. Für mich sieht es gut aus. Generika werden dort nichts Magisches für Sie tun. Es ist eine Besetzung; Sie sind nicht zufällig in der Sprache. Du bist gut. –

+0

@EdPlunkett Okay, danke! Ich wollte nur sicherstellen, dass es etwas gab, was ich nicht verstand. Prost. –

Antwort

3

Hier gibt es nichts zu verbessern. Die Umwandlung ist erforderlich, weil der Typ des Wörterbuchwerts MonoBehaviour ist. Sie wissen, dass es tatsächlich T ist, aber der Compiler nicht. Das musst du durch Casting sagen.

Sie haben es gut gemacht.

+0

Vielen Dank für die Erklärung! Ich wollte nur sicherstellen, dass ich nichts übersehen würde. Prost. –

+0

Ich denke, es gibt besseres als ein Wörterbuch mit Umwandlungen, wenn es nur eine Instanz pro Typ gibt, wie es scheint. Siehe meine Antwort. –

1

Wenn es nur eine Instanz pro Typ gibt, dann ist es besser. einen statischen generischen Typen betrachtet

using UnityEngine; 

public class ServiceManager : MonoBehaviour 
{ 
    // If this T confuses you from the generic T used elsewhere, rename it 
    public static Transform T { get; private set; } 

    void Awake() 
    { 
     T = transform; 
    } 

    public T Provide<T>() where T : MonoBehaviour 
    { 
     return ServiceMap<T>.service; // no cast required 
    } 
} 

static class ServiceMap<T> where T : MonoBehaviour 
{ 
    public static readonly T service; 

    static ServiceMap() 
    { 
     // Create service 
     GameObject serviceObject = new GameObject(typeof(T).Name); 
     serviceObject.transform.SetParent(ServiceManager.T); // make service GO our child 
     service = serviceObject.AddComponent<T>(); // attach service to GO 
    } 
} 

Mit dem Service ist einfach:

public class ServiceTest : MonoBehaviour 
{ 
    private void Start() 
    { 
     // no need to Create services 
     // They will be created when Provide is first called on them 
     // Though if you want them up and running at Start, call Provide 
     // on each here. 
    } 

    private void Example() 
    { 
     // Get a service 
     ServiceManager services = FindObjectOfType<ServiceManager>(); 
     MapService map = services.Provide<MapService>(); 
     // do whatever you want with map 
    } 
} 

Auch, wenn Sie dieser Arbeit nicht mehrere ServiceManagers dann haben.

Verwandte Themen