C# С;将变量转换为不带开关大小写的类型

C# С;将变量转换为不带开关大小写的类型,c#,C#,我有一个对象列表listoobjects,它们都是相同类型的,但具体类型未知(但是,我知道所有可能的类型)。有 许多可能的类型。每个对象都有一个属性Name,它是其类型的字符串。我想做如下事情: foreach (object elements in ListOfObjects) { // Some code here that casts elements into the specific type and pass it into another function } class

我有一个对象列表
listoobjects
,它们都是相同类型的,但具体类型未知(但是,我知道所有可能的类型)。有 许多可能的类型。每个对象都有一个属性
Name
,它是其类型的字符串。我想做如下事情:

foreach (object elements in ListOfObjects)
{
    // Some code here that casts elements into the specific type and pass it into another function
}
class Helper
{
    public static void Method(T input)
    {
        Console.WriteLine(input.GetType());
    }
}
我知道一种方法是使用switch case语句

  switch (ListOfObjects[0].Name)
  {
      case "Type1":
          //cast into Type1 and pass into function
      case "Type2":
          //cast into Type2 and pass into function
      default:
          //something
          break;
  }

有没有更干净的方法?是否可以将可能的类型存储在字典中并从该字典进行转换?

您实际上可以使用标准的系统属性和方法来实现您的目标

首先要做的是获取
类型

var type = System.Type.GetType(elements.Name, false, true);
false参数表示您不希望在出错时引发异常,true参数表示您希望忽略大小写

获得有效类型后,可以调用
System.Activator
来创建该类的新实例:

if (type != null) {
   var classInstance = System.ServiceActivator.CreateInstance(type);
   // Use the instance here
}

请注意,CreateInstance的此重载需要一个无参数的公共构造函数。但是,还有其他方法允许您传递参数和访问非公共构造函数。

您可以使用
Type.GetType
方法来获取对象的类型,而不是进行字符串比较。以下是相同的代码:

foreach (var element in ListOfObjects)
{
    var type = Type.GetType(element.Name);
    if (type == typeof(YOUR_OBJECT_TYPE))
    {
           // Do Something
    }

}

阅读更多关于
GetType

的信息如果您有重载,并且不想使用
开关,您可以使用
动态
,但是您确实需要问问自己这是否是一个设计问题,应该以更合适的方式解决。也就是说,为什么您需要在列表中存储不相关的类型

public static void Test(Version version)
{
   Console.WriteLine("is a version");
}
public static void Test(FormatException formatException)
{
   Console.WriteLine("is a formatException");
}
static void Main(string[] args)
{

   var list = new List<object>();
   list.Add(new Version());
   list.Add(new FormatException());

   foreach (var item in list)
      Test((dynamic)item);  
}

注意:如果找不到过载,这将全部中断。卡邦!所以我不建议你使用它,除非你真的需要 模式匹配 首先,我想介绍如何在switch语句中使用模式匹配来处理不同的类型,如下所示:

public static double ComputeAreaModernSwitch(object shape)
{
    switch (shape)
    {
        case Square s:
            return s.Side * s.Side;
        case Circle c:
            return c.Radius * c.Radius * Math.PI;
        case Rectangle r:
            return r.Height * r.Length;
        default:
            throw new ArgumentException(
                message: "shape is not a recognized shape",
                paramName: nameof(shape));
    }
}
例子取自


类型词典 有了它,是的,你可以写一本字典。。。问题在于物品的类型

我们可以这样做:

Dictionary<Type, Action<object>> dictionary;

// (initialize and populate somewhere else) ...

if (dictionary.TryGetValue(element.GetType(), out var action))
{
    action(element);
}
var methodInfo = typeof(Helper).GetMethod("Method");

// ...

methodInfo.Invoke(null, new object[]{element});
var helperType = typeof(Helper<>);

// ...

var specificMethodInfo = helperType.MakeGenericType(element.GetType()).GetMethod("Method");
specificMethodInfo.Invoke(null, new object[]{element});
var methodInfo = typeof(Helper).GetMethod("Method");

// ...

var specificMethodInfo = methodInfo.MakeGenericMethod(element.GetType());
specificMethodInfo.Invoke(null, new object[]{element});
var dataHandlers = types
            .SelectMany(t => t.GetTypeInfo().GetMethods())
            .Where(IsDataHandlerMethod)
            .Select(GetTypeDelegatePair);
您可以这样做:

Dictionary<Type, Action<object>> dictionary;

// (initialize and populate somewhere else) ...

if (dictionary.TryGetValue(element.GetType(), out var action))
{
    action(element);
}
var methodInfo = typeof(Helper).GetMethod("Method");

// ...

methodInfo.Invoke(null, new object[]{element});
var helperType = typeof(Helper<>);

// ...

var specificMethodInfo = helperType.MakeGenericType(element.GetType()).GetMethod("Method");
specificMethodInfo.Invoke(null, new object[]{element});
var methodInfo = typeof(Helper).GetMethod("Method");

// ...

var specificMethodInfo = methodInfo.MakeGenericMethod(element.GetType());
specificMethodInfo.Invoke(null, new object[]{element});
var dataHandlers = types
            .SelectMany(t => t.GetTypeInfo().GetMethods())
            .Where(IsDataHandlerMethod)
            .Select(GetTypeDelegatePair);
然后,您可以将所有方法放在一个helper类中,并通过名称(可以从类型的名称派生)找到它们


如果要调用具有泛型参数的已知方法,可以使用MethodInfo。我们需要知道方法是否是静态的,泛型参数是否是方法定义或声明类型定义的一部分

一方面,如果你有这样的东西:

class Helper<T>
{
    public static void Method(T input)
    {
        Console.WriteLine(input.GetType());
    }
}

注意:我将
null
作为要调用的第一个参数传递。这就是我调用该方法的实例。没有,因为它们是静态的。如果它们不是,那么您需要一个实例。。。例如,您可以尝试使用
Activator.CreateInstance
创建一个


附录:查找要调用的内容(类型发现) 也许您要调用不同的方法(它们不相同,但具有不同的泛型参数),但您不希望手工填充字典

这就是类型发现的用武之地

首先,我建议使用一个属性,例如:

[AttributeUsage(AttributeTargets.Method)]
public sealed class DataHandlerAttribute : Attribute { }
然后我们需要一个类型列表,我们将在其中搜索。如果我们要搜索已知程序集,我们可以执行以下操作:

var assembly = typeof(KnownType).GetTypeInfo().Assembly;
var types = assembly.GetTypes();
注意:如果您的目标平台不支持此(.NET标准1.0至1.4),则必须手动编写类型列表

接下来,我们需要一个谓词来检查给定类型是否是我们感兴趣的类型之一:

bool IsDataHandlerMethod(MethodInfo methodInfo)
{
    var dataHandlerAttributes = return (DataHandlerAttribute[])item.GetCustomAttributes(typeof(DataHandlerAttribute), true);
    if (attributes == null || attributes.Length == 0)
    {
        return false;
    }
    if (methodInfo.DeclaringType != null)
    {
        return false;
    }
    if (methodInfo.ReturnTpye != typeof(void))
    {
        return false;
    }
    var parameters = methodInfo.GetParameters();
    if (parameters.Length != 1)
    {
        return false;
    }
    if (paramters[0].IsByRef || paramters[0].IsOut)
    {
        return false;
    }
    return true;
}
以及将其转换为委托的方法:

(Type, Delegate) GetTypeDelegatePair(MethodInfo methodInfo)
{
    var parameters = methodInfo.GetParameters();
    var parameterType = parameters[0].ParameterType;
    var parameterTypeArray = new []{parameterType};
    var delegateType = typeof(Action<>).MakeGenericType(parameterTypeArray);
    var target = null;
    if (!methodInfo.IsStatic)
    {
        var declaringType = methodInfo.DeclaringType;
        target = instance = Activator.CreateInstance(declaringType);
    }
    return (parameterType, methodInfo.CreateDelegate(delegateType, target));
}
我们将有一个可枚举的类型对和委托对,可以用来填充字典


注意:上面的代码仍然需要一些工作(例如,我们可以只调用
GetParameters
一次吗?),并且假定是一个现代的.NET目标(需要额外的工作才能使它在较旧的平台上工作)。另外请注意,我提供的类型发现代码不处理泛型方法,您可以检查
Type.IsGenericTypeDefinition
MethodInfo.IsGenericMethodDefinition
。。。然而,我建议避免使用它们。事实上,如果您想将所有方法放在一个静态类中,那么修改它应该很容易。例如,您也可以使用类似的方法获取工厂方法。

我不确定是否清楚理解您的问题,但是, 也许它可以帮助你们,我不认为你们需要在名称字段中保留类型,因为你们可以像这样得到类型。我也不明白,为什么你想把这种类型的角色重新转换成它自己

foreach (var element in ListOfObjects)
{
var _type = element.getType()
}

您可以使用switch case或if语句来创建路由。

当然可以使用字典映射类型和方法:

Dictionary<Type, Action<Object>> methodMap = new Dictionary<Type, Action<Object>>();
Dictionary methodMap=newdictionary();
预加载字典:

static void Action1(Object obj)
{
  //do necessary casting here or not
  Console.WriteLine("i handle Type1");
}
static void Action2(Object obj)
{
   Console.WriteLine("i handle Type2");
}
Dictionary<Type, Action<Object>> methodMap = new Dictionary<Type, Action<Object>>();
methodMap[typeof(Type1)] = Action1;
methodMap[typeof(Type2)] = Action2;
List<Object> collector = new List<Object>();
collector.Add(new Type1());
collector.Add(new Type2());

methodMap[collector[0].GetType()](collector[0]);
methodMap[collector[1].GetType()](collector[1]);
静态无效操作1(对象对象对象)
{
//是否在这里进行必要的铸造
Console.WriteLine(“我处理类型1”);
}
静态无效操作2(对象obj)
{
Console.WriteLine(“我处理类型2”);
}
Dictionary methodMap=新建字典();
methodMap[typeof(Type1)]=Action1;
方法图[typeof(Type2)]=Action2;
并使用字典:

static void Action1(Object obj)
{
  //do necessary casting here or not
  Console.WriteLine("i handle Type1");
}
static void Action2(Object obj)
{
   Console.WriteLine("i handle Type2");
}
Dictionary<Type, Action<Object>> methodMap = new Dictionary<Type, Action<Object>>();
methodMap[typeof(Type1)] = Action1;
methodMap[typeof(Type2)] = Action2;
List<Object> collector = new List<Object>();
collector.Add(new Type1());
collector.Add(new Type2());

methodMap[collector[0].GetType()](collector[0]);
methodMap[collector[1].GetType()](collector[1]);
列表收集器=新列表();
collector.Add(新类型1());
collector.Add(新类型2());
methodMap[collector[0].GetType()](收集器[0]);
methodMap[collector[1].GetType()](收集器[1]);


类型方法映射也适用于那些不同的类。这将是您选择这种方法的关键因素,而不是重载或虚拟成员函数。

可能不是完全重复的,但概念相同:最近(及时更新)的一些答案讨论了
类型上的
切换。您可能还对C#8.0切换表达式(与语句相反)感兴趣。请参阅。它对你有用吗?为什么你不想申报一个ABS