简体   繁体   English

C# 从字符串名称实例化一个类

[英]C# Instantiate a Class from String name

Having multiple classes doing many things, I am obliged to instantiate one of them, populate some properties and call a method.让多个类做很多事情,我不得不实例化其中一个,填充一些属性并调用一个方法。 A sample would be having the below methods eg一个示例将具有以下方法,例如

        public class Method100Response201
    {
        public string R1_01 { get; set; }
        public void DoSpecialThing()
        { Console.WriteLine ("Something Blue..}"); }
    }
    public class Method100Response404
    {
        public string R2_01 { get; set; }
        public void DoSpecialThing()
        { Console.WriteLine ("Something Old..}"); }
    }
    public class Method110Response200
    {
        public string R3_01 { get; set; }
        public void DoSpecialThing()
        { Console.WriteLine ("Something New..}"); }
    }

all of them inside Program class in the same namespace, where I have the mechanism to find out which Class I need:所有这些都在同一个命名空间中的 Program 类中,在那里我有机制来找出我需要哪个类:

       static void Main(string[] args)
    {
        int[] MethodResponse = DoSomethingHere (23, "something", true);
        string DerivedClassName = ResponseModel(MethodResponse[0], MethodResponse[1]);
        Console.WriteLine (
            "For method " + MethodResponse[0].ToString () 
            + " and response " + MethodResponse[1].ToString ()
            + " you must instantiate Class " 
            + DerivedClassName);
        Console.ReadKey ();

        //how do I do this????
        //const string objectToInstantiate = "MyProject.Domain.MyNewTestClass, MyTestProject";
        //var objectType = Type.GetType (objectToInstantiate);
        //dynamic instantiatedObject = Activator.CreateInstance (objectType) as ITestClass;
        // set a property value
        //instantiatedObject.Name = DerivedClassName;
        // get a property value
        //string name = instantiatedObject.Name;

        // call a method - output "Something Blue.."
        //Console.Write (instantiatedObject.DoSpecialThing ());

    }

    public static int[] DoSomethingHere (int param1, string param2, bool whatever)
    {
        int firstInt = 0; int secondInt = 0;
        //
        //lots of work here, I end up with method and selector.. 
        //
        firstInt = 100;
        secondInt = 201;
        return new int[] { firstInt, secondInt };
    }

    public static string ResponseModel(int method, int response)
    {
        string returnClass = String.Empty;

        switch (method)
            {
            case 100:
                if (response == 201)
                { Console.WriteLine ("Case 100,201"); returnClass = "Method100Response201"; }
                else
                { Console.WriteLine ("Case 100,404"); returnClass = "Method100Response404"; }
                break;
            case 110:
                Console.WriteLine ("Case 100,404"); returnClass = "Method110Response200";
                break;
            case 120:
                // ...
                break;
            }
        return returnClass;
    }

I tried with something called Activator, I am no expert and this is really critical for me.我尝试了一种叫做 Activator 的东西,我不是专家,这对我来说真的很重要。 Could someone please help me?有人可以帮我吗? (I left commented on some code I am trying to, based on published solutions here in SO. Thank you). (基于 SO 中已发布的解决方案,我对我正在尝试的一些代码发表了评论。谢谢)。

This technical called Reflection, that means call an instance from string.这个技术叫做反射,意思是从字符串中调用一个实例。 My calling class will be我的电话课将是

public class Class1
{
    public string Property { get; set; } = "I'm class1";
    public void DoSpecialThings()
    {
        Console.WriteLine("Class1 does special things");
    }
}

Next I create an instance in a static function, should put your all classes in a same namespace to easy control接下来我在静态函数中创建一个实例,应该将所有类放在同一个命名空间中以便于控制

    public static dynamic GetClassFromString(string className)
    {
        var classAddress = $"NetCoreScripts.{className}";
        Type type = GetType(classAddress);

        // Check whether the class is existed?
        if (type == null)
            return null;

        // Then create an instance
        object instance = Activator.CreateInstance(type);

        return instance;
    }

And a GetType method和一个 GetType 方法

    public static Type GetType(string strFullyQualifiedName)
    {
        Type type = Type.GetType(strFullyQualifiedName);
        if (type != null)
            return type;
        foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
        {
            type = asm.GetType(strFullyQualifiedName);
            if (type != null)
                return type;
        }
        return null;
    }

I use dynamic type to implement quickly, basically you can use interface for explicit coding.我用动态类型来快速实现,基本上你可以使用接口进行显式编码。

    static async Task Main(string[] args)
    {
        dynamic instance = GetClassFromString("Class1");

        Console.WriteLine(instance.GetType().FullName); //NetCoreScripts.Class1

        Console.WriteLine(instance.GetType().Name); //Class1

        Console.WriteLine(instance.Property); //I'm class1

        instance.Property = "Class1 has been changed";
        Console.WriteLine(instance.Property); //Class1 has been changed

        instance.DoSpecialThings(); // Class1 does special things
    }

The problem that you are trying to solve is with regard Creation of new objects.您要解决的问题与创建新对象有关。Here are some common coding patterns used for the same.以下是一些常用的编码模式。

I would say this is a good use case for Factory pattern.我会说这是工厂模式的一个很好的用例。 What we do is delegate the responsibility for creating objects to a factory .我们所做的是将创建对象的责任委托给工厂

Firstly, we can identify them as classes that extend an abstract class首先,我们可以将它们标识为扩展抽象类的类

public abstract class MehodResponseBase {
    public abstract void  DoSpecialThing();
    public abstract string responseText;
}

public class Method100Response201 : MehodResponseBase
{
    public override responseText = "Method100Response201";
    public string R1_01 { get; set; }
    public override void DoSpecialThing()
    { Console.WriteLine ("Something Blue..}"); }
}
public class Method100Response404 : MehodResponseBase
{
    public override responseText = "Method100Response404";

    public string R2_01 { get; set; }
    public override void DoSpecialThing()
    { Console.WriteLine ("Something Old..}"); }
}
public class Method110Response200 : MehodResponseBase
{
    public override responseText = "Method110Response200";

    public string R3_01 { get; set; }
    public override void DoSpecialThing()
    { Console.WriteLine ("Something New..}"); }
}

Then we can extract their creation into a factory然后我们可以将他们的创作提取到一个工厂中

pubic class MethodResponseFactory() 
{
    public static MehodResponseBase Make(int method, int response)
    {
        if (method == 100) 
        {
            if(response == 201) 
            {
                return new Method100Response201();
            }

            if(response == 404) 
            {
                return new Method100Response404();
            }
        }

        if (method == 110) 
        {
            if (response == 200) 
            {
                return new Method110Response200();
            }
        }

        throw new MethodResponseCreationException($"Cannot create for mothod: {method} and response: {response}")
    }

}

So your response model is refactored to所以你的响应模型被重构为

public static string ResponseModel(int method, int response)
{
        try 
        {
            return MethodResponseFactory.Make(method, response).returnClass;
        }
        catch (MethodResponseCreationException ex)
        {
            return string.Empty;
        }
}

So, as you can see, all the delegation for creating the object is now in the factory.因此,如您所见,创建对象的所有委托现在都在工厂中。 And resonseModel class simply calls the factory to build a class based on the method and response .resonseModel类只是简单地调用工厂来构建一个基于methodresponse

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM