创建未知类型的实例

时间:2016-05-28 23:38:35

标签: c# reflection

我很确定有几种不同的方法可以做到这一点,因为我非常接近它而没有成功使用像 Activator.CreateInstance 这样的东西,但我希望看到你对我的具体案例的意见

有没有办法避免这种开关?

b = [[-1, 2], [-2, 1], [0, 4], [3, 5], [-3, 1], [-10, -7], [6, 8]]
b.sort()
result = []
current = b[0]
for interval in b[1:]:
    if current[1] >= interval[0]:
        current[1] = interval[1]
    else:
        result.append(current)
        current = interval
result.append(current)
print(result)  # [[-10, -7], [-3, 5], [6, 8]]

3 个答案:

答案 0 :(得分:5)

我的方法是使用字典来构建映射。字典可以在运行时修改,如果需要可以使用反射动态填充。

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

Resource r = factory[type].Invoke();

答案 1 :(得分:2)

如果类型名称相同,则不必从枚举中保存映射,否则可以使用Dictionary来保存映射。

这是另一个使用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
{
}

答案 2 :(得分:2)

另一种方法是使用属性标记您的类型,搜索所有这些标记的类型,然后根据所选的枚举值激活类型。

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 );
    }
}