C# 键入调用Activator.CreateInstance()实例的方法的安全方式?
在下面的代码中,C# 键入调用Activator.CreateInstance()实例的方法的安全方式?,c#,C#,在下面的代码中,hs.Add(…)无法编译。声明hs为dynamic应该可以工作,但我尽量不使用它。有没有一种类型安全的方法 void F(string colName, DbDataReader reader1, DbDataReader reader2) { // .... loop reader1.Read(); reader2.Read() var x = reader1[colName]; var type = x.GetType(); var hs =
hs.Add(…)
无法编译。声明hs
为dynamic
应该可以工作,但我尽量不使用它。有没有一种类型安全的方法
void F(string colName, DbDataReader reader1, DbDataReader reader2)
{
// .... loop reader1.Read(); reader2.Read()
var x = reader1[colName];
var type = x.GetType();
var hs = Activator.CreateInstance(typeof(HashSet<>).MakeGenericType(type));
// change var to dynamic will work. Trying not to use it.
hs.Add(x); // Error
// ...
hs.Contains(reader2[colName]); // Error
但它有一个错误
System.InvalidCastException: Unable to cast object of type
'System.Collections.Generic.HashSet`1[System.Int32]' to type
'System.Collections.Generic.HashSet`1[System.Object]'.
正如Peter指出的,
Activator
是一种使用反射动态创建对象的方法,而不需要在构建时知道对象的类型。此方法中的类型“安全”是通过检查类型或处理类型转换错误,如使用Convert.ChangeType
请注意,DbDataReader有一些帮助函数用于处理诸如GetFieldType和GetString之类的类型,这些类型可以使用列索引来调用。例如:
int myColumn = 0;
var type = reader1.GetFieldType(myColumn);
if (type == typeof(string))
string myValue = reader1.GetString(myColumn);
它或多或少归结为一些使用分支语句而不是反射来管理类型的方法。另外,您应该注意到,许多ORM(如EntityFramework或Dapper)都为您处理了大量此类类型转换。正如Peter指出的,
Activator
是一种使用反射来动态创建对象的方法,而在构建时不知道对象的类型。此方法中的类型“安全”是通过检查类型或处理类型转换错误,如使用Convert.ChangeType
请注意,DbDataReader有一些帮助函数用于处理诸如GetFieldType和GetString之类的类型,这些类型可以使用列索引来调用。例如:
int myColumn = 0;
var type = reader1.GetFieldType(myColumn);
if (type == typeof(string))
string myValue = reader1.GetString(myColumn);
它或多或少归结为一些使用分支语句而不是反射来管理类型的方法。另外,您应该注意到,许多ORM(如EntityFramework或Dapper)为您处理了大量此类类型转换。您似乎希望对标量值执行某种设置操作(交集?排除?)。您可以使用泛型(和
DbDataReader.GetFieldValue
)解决此问题,而无需使用反射或Activator
,如下所示:
如果要从静态(即编译时)已知colName
列类型的调用站点调用此F
函数,请将F
转换为通用方法:
void F<T>( String colName, DbDataReader reader1, DbDataReader reader2 )
{
Itn32 rdr1Idx = reader1.GetOrdinal( colName );
Itn32 rdr2Idx = reader2.GetOrdinal( colName );
HashSet<T> hashSet = new HashSet<T>();
while( reader1.Read() && reader2.Read() )
{
T value1 = reader1.GetFieldValue<T>( rdr1Idx );
T value2 = reader2.GetFieldValue<T>( rdr2Idx );
hashSet.Add( value1 );
hashSet.Add( value2 );
// etc - whatever logic you want here.
}
}
似乎您想要对标量值执行某种集合操作(交集?排除?)。您可以使用泛型(和
DbDataReader.GetFieldValue
)解决此问题,而无需使用反射或Activator
,如下所示:
如果要从静态(即编译时)已知colName
列类型的调用站点调用此F
函数,请将F
转换为通用方法:
void F<T>( String colName, DbDataReader reader1, DbDataReader reader2 )
{
Itn32 rdr1Idx = reader1.GetOrdinal( colName );
Itn32 rdr2Idx = reader2.GetOrdinal( colName );
HashSet<T> hashSet = new HashSet<T>();
while( reader1.Read() && reader2.Read() )
{
T value1 = reader1.GetFieldValue<T>( rdr1Idx );
T value2 = reader2.GetFieldValue<T>( rdr2Idx );
hashSet.Add( value1 );
hashSet.Add( value2 );
// etc - whatever logic you want here.
}
}
下面是使用反射的版本
var x = 1;
var type = x.GetType();
var hs = Activator.CreateInstance(typeof(HashSet<>).MakeGenericType(type));
// hs.Add(x); // Error
var method = hs.GetType().GetMethod("Add");
method.Invoke(hs, new object[] { x });
method.Invoke(hs, new object[] { x + 1 });
var x=1;
var type=x.GetType();
var hs=Activator.CreateInstance(typeof(HashSet).MakeGenericType(type));
//加上(x);//错误
var method=hs.GetType().GetMethod(“添加”);
调用(hs,新对象[]{x});
调用(hs,新对象[]{x+1});
如果
.Invoke()
需要被调用数百万次,那么它比dynamic
要慢<代码>动态似乎需要更多的时间进行设置。这是使用反射的版本
var x = 1;
var type = x.GetType();
var hs = Activator.CreateInstance(typeof(HashSet<>).MakeGenericType(type));
// hs.Add(x); // Error
var method = hs.GetType().GetMethod("Add");
method.Invoke(hs, new object[] { x });
method.Invoke(hs, new object[] { x + 1 });
var x=1;
var type=x.GetType();
var hs=Activator.CreateInstance(typeof(HashSet).MakeGenericType(type));
//加上(x);//错误
var method=hs.GetType().GetMethod(“添加”);
调用(hs,新对象[]{x});
调用(hs,新对象[]{x+1});
如果
.Invoke()
需要被调用数百万次,那么它比dynamic
要慢<代码>动态似乎需要更多的时间来设置。什么是参数
?为什么动态工作?你的问题很具体。到目前为止你试过什么?您是否要记住,一旦您选择了动态/反射路线,您将无法以非类型化操作的方式执行所有操作,直到您返回到编译时已知的类型,或者编译新的类型安全代码以执行(例如,使用表达式
)更新<代码>hs.添加(x)
。问题是关于不使用动态
。您的问题仍然不清楚。正如我已经指出的,如果您想要编译时安全(即类型安全),那么您必须在编译时知道类型。dynamic
类型允许在运行时进行编译,这是解决问题的一种方法。动态构建表达式树是解决此问题的另一种方法(这只是在运行时编译代码的另一种方法)。基本上,任何允许您在运行时编译代码的机制都可以工作,而其他机制则不行。您尝试过什么?提示:除非您使用的是匿名类型,否则不要使用var
关键字var
与说“我不在乎这是什么类型”(对于那种用法Object
)是两码事。通过使用var
您无法立即看到x
的静态类型是什么。@对于此类问题,Dai是一个很好的建议。。。问题中x
的类型实际上是Object
:)什么是paramX
?为什么动态工作?你的问题很具体。到目前为止你试过什么?您是否要记住,一旦您选择了动态/反射路线,您将无法以非类型化操作的方式执行所有操作,直到您返回到编译时已知的类型,或者编译新的类型安全代码以执行(例如,使用表达式
)更新<代码>hs.添加(x)
。问题是关于不使用动态
。您的问题仍然不清楚。正如我已经指出的,如果您想要编译时安全(即类型安全),那么您必须在编译时知道类型。dynamic
类型允许在运行时进行编译,这是解决问题的一种方法。动态构建表达式树是解决此问题的另一种方法(这只是在运行时编译代码的另一种方法)。基本上,任何允许你