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