2

Am pretty sure there is a few different ways of doing this, as i got very close to it without success with stuff like Activator.CreateInstance, but i wanted to see your opinion on my specific case.

Is there a way to avoid this kind of switches?

Resource r = null; < --Resource is the base class of block,rock,plant types.

switch (type) //type is a byte you get from somewhere on runtime
{
        //Then you instantiate that class type depending on that "type byte",
        //simply by comparing it to an enum lets say

    case ResourceType.Block:
        r = new Block();
        break;
    case ResourceType.Rock:
        r = new Rock();
        break;
    case ResourceType.Plant:
        r = new Plant();
        break;
 }

//Then you apply some data to that newly created 'resource"
r.id = id;

//Then you save that 'resource' into a dictionary of resources.
ResourceDatabase.Add(r.id, r);
2
  • 1
    Interfaces to the rescue? Commented May 28, 2016 at 23:40
  • 1
    When asking a question you should include a minimal reproducible example. This means I should be able to copy your code and run it without needing to re-invent your types. Please include your enum and class types. Commented May 28, 2016 at 23:54

3 Answers 3

5

My approach would be to use a dictionary to build up the mapping. The dictionary can be modified at run-time and can be dynamically populated using reflection if need be.

var factory = new Dictionary<ResourceType, Func<Resource>>()
{
    { ResourceType.Block, () => new Block() },
    { ResourceType.Rock, () => new Rock() },
    { ResourceType.Plant, () => new Plant() },
};

Resource r = factory[type].Invoke();
Sign up to request clarification or add additional context in comments.

Comments

2

You don't have to hold a mapping from enum if the type names are identical, else you can use Dictionary to hold the mapping.

Here is another example using only the exact name of the object type, using Activator.CreateInstance.

using System;

public class Program
{
    public static void Main()
    {
        string dog = "Dog";
        var dogObj = Activator.CreateInstance(Type.GetType(dog)) as Animal;
        string cat = "Cat";
        var catObj = Activator.CreateInstance(Type.GetType(cat)) as Animal;
        Console.WriteLine(dogObj);
        Console.WriteLine(catObj);
    }
}

public abstract class Animal
{
    public override string ToString() { return "Type: " + GetType().Name; }
}

public class Cat : Animal
{
}

public class Dog : Animal
{
}

Comments

2

Another approach would be to label your types with attributes, search for all such-labeled types, and then activate the types based on the chosen enumeration value.

public enum ResourceType
{
    Plant,
    Rock,
    Block
}

[AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=false)]
public class ResourceDeclAttribute : Attribute
{
    public ResourceDeclAttribute( ResourceType resType )
    {
        this.ResType = resType;
    }

    public ResourceType ResType { get; private set; }
}

public class Resource
{
    // ...
}

[ResourceDecl( ResourceType.Plant )]
public class Plant : Resource
{ 
    // ...
}

[ResourceDecl( ResourceType.Block )]
public class Block : Resource
{
    // ...
}

[ResourceDecl( ResourceType.Rock )]
public class Rock : Resource
{
    // ...
}


public class Loader
{
    private Dictionary<ResourceType, Type> enumToTypeMap;

    public Loader()
    {
        this.enumToTypeMap = new Dictionary<ResourceType, Type>();
    }

    public void Initialize()
    {
        Assembly targetAssembly;

        // Fill in with the right way to identify your assembly. One trick is to have a dummy
        // class in the assemblies that define your types, make a hard reference to those
        // classes, and then use the class's types to find out what assembly they came from.

        targetAssembly = Assembly.GetExecutingAssembly();

        Type[] exportedTypes = targetAssembly.GetExportedTypes();

        foreach( Type candidate in exportedTypes )
        {
            ResourceDeclAttribute attrib = candidate.GetCustomAttribute<ResourceDeclAttribute>();

            if( attrib != null )
            {
                this.enumToTypeMap.Add( attrib.ResType, candidate );
            }
        }
    }

    public Resource Activate( ResourceType resType )
    {
        Type res = this.enumToTypeMap[resType];

        return (Resource)Activator.CreateInstance( res );
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.