【问题标题】:C# pass class as string and cast it from arrayC#将类作为字符串传递并从数组中转换
【发布时间】:2013-04-14 03:13:21
【问题描述】:

我几乎没有嵌套类,例如“BlueprintsManager.WorkingStandardBlueprint”,以及具有它们实例的 ArrayList。我想将它们作为参数传递给方法,例如:

private void ShowBlueprints(string class_str, ArrayList class_array)
{
    // class_str would be passed as "BlueprintsManager.WorkingStandardBlueprint"
    // how here I can access class_str as a class and cast class_array to it, to access some variables.
    // for example, I need to access some BlueprintsManager.WorkingStandardBlueprint public variables.
}

我一直在搞反射,泛型,但我仍然无法让它工作。

谢谢。

【问题讨论】:

  • 那么class_str是类名,class_array是什么?它是对象的集合,其中一个(或全部)属于class_str定义的类型???
  • 是的,class_array 将是类实例的列表,所以如果将 class_str 作为“BlueprintsManager.WorkingStandardBlueprint”传递,我想将 class_array[0] 转换为 class_str。
  • 你用的是什么版本的c#
  • 如果是 4.0 及以上版本试试这个动态 printObj=class_array[0] 并访问属性为 printObj.property1 ,你不需要传递类名
  • 不幸的是它是 2.x :-)

标签: c# generics reflection types casting


【解决方案1】:

你应该为此使用泛型:

private void ShowBlueprints<T>(List<T> class_array)
{
    for (BlueprintsManager.WorkingStandardBlueprint item in class_array)
    {
        if(typeof T is BlueprintsManager.WorkingStandardBlueprint)
        {
            Console.WriteLine(((BlueprintsManager.WorkingStandardBlueprint)item).whateverpropertyyouhavedefined);
        }
    }
}

现在你可以像这样调用方法了:

ShowBluePrints<BlueprintsManager.WorkingStandardBlueprint>(myblueprints);

EDIT 在 cmets 中,OP 说所有属性都是相同的。该解决方案可行:

class BaseClass
{
    string Name {get; set;}
    int id {get; set;}
}

class BlueprintsManager
{
    class WorkingStandardBlueprint : BaseClass
    {

    }
}

private void ShowBlueprints<T>(List<T> class_array) where T : BaseClass
{
    for (T item in class_array)
    {       
        Console.WriteLine(item.Name);
    }
}

【讨论】:

  • 是的,这很好,而且有效,但是我有很多这些嵌套类,所以这是使用类名传递字符串的主要原因,所以在函数中我不需要知道我是什么类过去了以您的示例为例,我需要为每个班级编写 if,这就是我要避免的。或者我不明白你的回答。 :-)
  • 如果你不知道你有什么类,你将如何访问函数中的属性?如果所有属性都相同,则创建一个基类。您可以使用通用约束来确保该方法只接受基类的子类。所有属性都一样吗?
  • 是的,它们都是一样的。我需要访问两个变量,字符串名称和 int id。
  • OK,然后创建一个基类并为您的泛型方法指定一个约束。让您的所有类都继承基类。我编辑了我的答案给你看一个例子
  • 效果非常好!非常感谢,真的。我欠你一杯啤酒。
【解决方案2】:

我认为问题在于why 而不是如何。我没有看到很多这样的结构。

如果满足您的需要,您应该使用泛型。

如果你真的需要从任意列表中construct types dynamically

1) 制作一个通用方法(就像已经建议的那样)

interface IBlueprint
{
    int ID {get;set;}
    int Name {get;set;}
}
class MyClass 
{
    private void ShowBlueprints<T>(IEnumerableT> values) where T : IBlueprint 
    {
        // access properties of IBlueprint
    }
    // I presume you 'know something' about your 'T'-s, have an interface -
    // ...if you don't you should if possible
}

2) 并这样称呼它(我从记忆中输入,但它应该是正确的)

MyClass myclass = new MyClass();
var values = // list of your blueprints
// if you don't have any in the list handle it and bail out
MethodInfo methodInfo = typeof(MyClass).GetMethod("ShowBlueprints");
MethodInfo methodInfoGeneric = 
    methodInfo.MakeGenericMethod(new[] { values.First().GetType() });
// or get your blueprint type from string if needed
methodInfoGeneric.Invoke(myclass, new object[] { values });  

【讨论】:

    【解决方案3】:

    您不能将对象转换为仅通过其字符串名称知道的类型。因此,您也无法以这种方式访问​​其字段。您有一些选项可以访问类型的字段:

    1. 您知道确切的类型(或其任何基本类型或接口),因此您可以直接强制转换:

      object first = class_array[0];
      var blueprint = (BlueprintsManager.WorkingStandardBlueprint)first;
      blueprint.MyProperty = 10;
      
    2. 您不知道确切的类型,但您非常确定它有一个具有特定名称的公共属性/字段。请注意此处的 dynamic 关键字,适用于 C# 4 及更高版本。

      dynamic blueprint = class_array[0];
      blueprint.MyProperty = 10;
      
    3. 您不知道确切的类型,但您会得到一个带有类型名称的字符串。而且您不知道确切的属性/字段,但您会得到一个带有属性名称的字符串。然后你可以使用反射:

      string typeName = "BlueprintsManager.WorkingStandardBlueprint";
      string propertyName = "MyProperty";
      
      var type = Assembly.GetExecutingAssembly().GetType(typeName);
      var property = type.GetProperty(propertyName);
      
      object first = class_array[0];
      // Getter:
      int result = (int)property.GetMethod.Invoke(first, null);
      // Setter
      property.SetMethod.Invoke(first, new object[] { 10 });
      

    顺便说一句,您不应该使用ArrayList。当泛型还不存在时,它是一个非常古老的类。今天你应该使用List&lt;T&gt;。例如,当您知道所有T 使用您要使用的属性实现接口IBlueprint 时:

    private void ShowBlueprints<T>(string classStr, List<T> classArray)
        where T : IBlueprint
    {
        T blueprint = classArray[0];
        blueprint.MyProperty = 10;
    }
    

    或者如果你真的有一个任何类型的对象列表:

    private void ShowBlueprints(string classStr, List<object> classArray);
    

    【讨论】:

    • 我无法从 PropertyInfo 调用“GetMethod”。我正在使用单声道,也许它缺少smth。
    猜你喜欢
    • 2020-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多