我有一个object
类型变量,我想将其转换为其原始数据类型。数据类型可以是任何类型(int, enum, class等)
(object.GetType())object
不工作
编辑:
我想再次将其转换为原始的原因,因为我正在构建一个具有多个参数的cosmos db查询
我有一个方法QueryCosmos(Dictionary<string, object> parameters)
,其中键是cosmos中的字段名,值是匹配条件的字段的值(它可以是任何数据类型)。
static string QueryCosmos(Dictionary<string, object> parameters)
{
var sb = new StringBuilder($"SELECT * FROM c WHERE ");
foreach (var p in parameters)
{
if (!(p.Value is string))
{
// this handles non-string data types
var value = p.Value == null ? "null" : p.Value.ToString().ToLower();
sb.Append($"c.{p.Key} = {value} and ");
}
else
{
sb.Append($"c.{p.Key} = '{p.Value}' and ");
}
}
return sb.ToString().Substring(0, sb.ToString().LastIndexOf(" and "));
}
我的问题是这行代码var value = p.Value == null ? "null" : p.Value.ToString().ToLower();
如果我传递一个enum
类型,不匹配宇宙中的数据。因为在cosmos中,这是作为枚举的数值存储的。我需要将其转换为numeric
值。可以传递多种可能的enum
类型。这就是为什么我想用一种动态的方式转换为原始数据类型
的原因。希望这能消除人们的担忧
当你的目标是Azure CosmosDB时,你不需要编写自己的查询生成器,CosmosDB客户端库(Microsoft.Azure.Cosmos
)有一个内置的。
在您的示例中,使用QueryDefinition
和WithParameter
来构建强类型查询。WithParameter
方法接受值作为object
,并为您处理特定类型的逻辑。
当你使用动态查询时,我下面的代码展示了如何通过使用命名参数从字典中安全地构建查询的WHERE
子句。
永远不要在查询SQL本身中直接嵌入查询参数值因为这样做会导致SQL注入,这是非常糟糕的事情。
更新enum
:
我承认我不熟悉Azure CosmosDB客户端库,尽管我确实快速浏览了文档并在ILSpy中浏览了库。
对于enum
值的处理:QueryDefinition.WithParameter
方法应该正确处理enum
值,因为它在.Value
属性中保留了盒装enum值。
如果没有,那么将任何enum
转换为Int32
可以这样做-尽管有装箱(虽然是可以将任何enum转换为Int64
而不需要转换,这需要运行时IL发出超出此答案的范围,但如果你感兴趣,我在我的GitHub gist中有一个实现):
我已经更新了下面的代码,使用这个foreach
循环来检查Enum
(它匹配任何和所有enum
类型,不管它们的底层类型如何,尽管这个例子将失败,如果您有任何enum : Int64
枚举的值超出Int32
的范围-但这是微不足道的修复,因此留给读者作为练习)。
foreach( var kvp in parameters )
{
if( kvp.Value is Enum e )
{
Int32 enumAsInt32 = (Int32)Convert.ChangeType( e, TypeCode.Int32 );
query = query.WithParameter( kvp.Key, enumAsInt32 );
}
else
{
query = query.WithParameter( kvp.Key, kvp.Value );
}
}
原始答案的其余部分:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
//
public static QueryDefinition BuildCosmosQuery( Dictionary<String,Object> parameters )
{
String sqlText = "SELECT * FROM foobar AS f WHERE " + GetWhereClauses( "f", parameters.Keys );
QueryDefinition query = new QueryDefinition( sqlText );
foreach( var kvp in parameters )
{
if( kvp.Value is Enum e )
{
Int32 enumAsInt32 = (Int32)Convert.ChangeType( e, TypeCode.Int32 );
query = query.WithParameter( kvp.Key, enumAsInt32 );
}
else
{
query = query.WithParameter( kvp.Key, kvp.Value );
}
}
return query;
}
private static String GetWhereClauses( String tableAlias, IEnumerable<String> parameterNames )
{
return parameterNames
.Select( pn => "{0}.{1} = @{1}".FmtInv( tableAlias, pn ) )
.StringJoin( separator: " AND " );
}
//
public static class Extensions
{
public static String StringJoin( this IEnumerable<String> source, String separator )
{
return String.Join( values: source, separator: separator );
}
public static String FmtInv( this String format, params Object[] args )
{
return String.Format( CultureInfo.InvariantCulture, format, args: args );
}
}
请参阅本代码示例中的QueryWithSqlParameters
方法,了解如何使用QueryDefinition
。
我没有看过你的新编辑,但希望我的答案仍然是相关的。
如果你希望将一个实例强制转换为它已知的具体类类型,那么你可以使用as
操作符。
下面是一些示例代码:
using System.IO;
using System;
using System.Collections.Generic;
class Program
{
public class BaseClass{
public string Base="BaseClass";
}
public class Class1:BaseClass{
public string Value="Class 1";
}
public class Class2:BaseClass{
public string Value="Class 2";
public string AnotherValue="Another value";
}
static void Main()
{
List<BaseClass> list=new List<BaseClass>(){new Class1(), new Class2()};
foreach( var item in list)
{
Console.WriteLine($"Item.Base = {item.Base}");
if(typeof(Class1).IsAssignableFrom( item.GetType() ))
{
Console.WriteLine($"Item.Value = {(item as Class1).Value}");
}
if(typeof(Class2).IsAssignableFrom( item.GetType() ))
{
Console.WriteLine($"Item.Value = {(item as Class2).Value}");
Console.WriteLine($"Item.Value = {(item as Class2).AnotherValue}");
}
}
}
}
这将给你输出:
Item.Base = BaseClass
Item.Value = Class 1
Item.Base = BaseClass
Item.Value = Class 2
Item.Value = Another value