C# 如何获取带参数的Ctor的ConstructorInfo
我正在尝试编写接收参数列表并获取匹配的构造函数信息的代码 方法签名是C# 如何获取带参数的Ctor的ConstructorInfo,c#,reflection,constructor,system.reflection,system.type,C#,Reflection,Constructor,System.reflection,System.type,我正在尝试编写接收参数列表并获取匹配的构造函数信息的代码 方法签名是ConstructorInfo GetConstructorInfo(类型,对象[]args) 我创建了一个类来处理: public class ClassWithParamsInCtor { public ClassWithParamsInCtor(params int[] parameters) { } } 使用Activatorclass I可以创建此对象的实例: ClassWithParams
ConstructorInfo GetConstructorInfo(类型,对象[]args)
我创建了一个类来处理:
public class ClassWithParamsInCtor
{
public ClassWithParamsInCtor(params int[] parameters)
{
}
}
使用Activator
class I可以创建此对象的实例:
ClassWithParamsInCtor myclass = Activator.CreateInstance(typeof(ClassWithParamsInCtor), new object[] { 1,2 }) as ClassWithParamsInCtor; \\returns a valid instance of the class;
但是当我试图获取ConstructorInfo时,出现了一个问题,下面返回null:
ConstructorInfo ctorInfo = typeof(ClassWithParamsInCtor).GetConstructor(new Type[] { typeof(int), typeof(int) }); \\returns null
在这种情况下,如何获取ConstructorInfo 试试这个
ConstructorInfo ctorInfo = typeof(ClassWithParamsInCtor).GetConstructor(new Type[] { typeof(int[])});
希望有帮助,
参数int[]
是int[]
的语法糖,您需要使用typeof(int[])
如果我理解正确,我想我有办法解决你的问题 假设您拥有以下类别:
public class ClassWithParamsInCtor
{
public ClassWithParamsInCtor(params int[] parameters)
{
}
public ClassWithParamsInCtor(int[] parameters, double y)
{
}
public ClassWithParamsInCtor(int[] parameters, float y)
{
}
}
下面是一些单元测试,它们描述了我实现的解决方案:
[TestClass]
public class TestClassWithParamsInCtorClass
{
[TestMethod]
//Wrong data type test
public void WrongInputDataTypesTest()
{
//Arrange
var inputData = new object[] { new[] { 1, 2 }, "" };
var inputDataTypes = inputData.Select(_ => _.GetType());
//Act
var matchedCtorParams = typeof(ClassWithParamsInCtor)
.GetConstructors()
.Select(_ => _.GetParameters().Select(a => a.ParameterType))
.Where(_ => _.HaveSameItems(inputDataTypes)).ToArray();
//Assert
Assert.AreEqual(null, matchedCtorParams.FirstOrDefault());
}
[TestMethod]
//Test used to invoke first constructor
public void InputDataTypesTest1()
{
//Arrange
var inputData = new object[] { new[] { 1, 2 } , 1 };
var inputDataTypes = inputData.Select(_ => _.GetType());
//Act
var matchedCtorParams = typeof(ClassWithParamsInCtor)
.GetConstructors()
.Select(_ => _.GetParameters().Select(a => a.ParameterType))
.Where(_ => _.HaveSameItems(inputDataTypes)).ToArray();
var result = typeof(ClassWithParamsInCtor).GetConstructor(matchedCtorParams.FirstOrDefault().ToArray())
.Invoke(inputData);
//Assert
Assert.AreNotEqual(null, result);
}
[TestMethod]
//Test used to invoke second constructor
public void InputDataTypesTest2()
{
//Arrange
var inputData = new object[] { new[] { 1, 2 }, 1.2 };
var inputDataTypes = inputData.Select(_ => _.GetType());
//Act
var matchedCtorParams = typeof(ClassWithParamsInCtor)
.GetConstructors()
.Select(_ => _.GetParameters().Select(a => a.ParameterType))
.Where(_ => _.HaveSameItems(inputDataTypes)).ToArray();
var result = typeof(ClassWithParamsInCtor).GetConstructor(matchedCtorParams.FirstOrDefault().ToArray())
.Invoke(inputData);
//Assert
Assert.AreNotEqual(null, result);
}
[TestMethod]
//Test used to invoke third constructor
public void InputDataTypesTest3()
{
//Arrange
var inputData = new object[] { new[] { 1, 2 }, 3.5F };
var inputDataTypes = inputData.Select(_ => _.GetType());
//Act
var matchedCtorParams = typeof(ClassWithParamsInCtor)
.GetConstructors()
.Select(_ => _.GetParameters().Select(a => a.ParameterType))
.Where(_ => _.HaveSameItems(inputDataTypes)).ToArray();
var result = typeof(ClassWithParamsInCtor).GetConstructor(matchedCtorParams.FirstOrDefault().ToArray())
.Invoke(inputData);
//Assert
Assert.AreNotEqual(null, result);
}
}
我使用的扩展方法是:
public static bool HaveSameItems<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
var dictionary = a.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count());
foreach (var item in b)
{
int value;
if (!dictionary.TryGetValue(item, out value))
{
return false;
}
if (value == 0)
{
return false;
}
dictionary[item] -= 1;
}
return dictionary.All(x => x.Value == 0);
}
public static bool HaveSameItems(此IEnumerable a,IEnumerable b)
{
var dictionary=a.GroupBy(x=>x).ToDictionary(g=>g.Key,g=>g.Count());
foreach(b中的var项目)
{
int值;
if(!dictionary.TryGetValue(项,输出值))
{
返回false;
}
如果(值==0)
{
返回false;
}
字典[项目]-=1;
}
返回dictionary.All(x=>x.Value==0);
}
我很确定单元测试可以实现得更细粒度,但考虑到这是概念证明,我觉得它们很不错。谢谢Berkay!这很有帮助,但当这不是ctor的唯一参数时,仍然存在一个问题。例如,如果Ctor得到一个双x和参数int[]args,并且我的方法被传递了一个对象[],该对象为[3.5,1,2]。如果参数类型为int,我可以开始贪婪地匹配参数,但我希望有更好的方法谢谢Selman!这在上述情况下确实有帮助,但我仍然有一个问题。我已经在给Berkay的评论中详细解释了这个问题,我将不胜感激help@Belgi当ur方法采用
double
和params int[]
使用新类型[]{typeof(double),typeof(int[])}
时,问题是我事先不知道如何解构我接收的对象[],这是一段通用代码,用于调用不同的types@Belgi嗯,在这种情况下,您可以试着获取类型数组:args.Select(x=>x.GetType()).ToArray()
并将其传递给GetConstructor
,但这对params ofc不起作用。当您传递两个整数时,它将返回两个typeof(int)
,您需要专门处理参数,因为参数列表末尾定义了参数,请检查参数末尾是否包含相同类型的参数,例如如果它是double,string,int,int,int
,您可以检查是否有接受double的构造函数,字符串和int[]数组
public static bool HaveSameItems<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
var dictionary = a.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count());
foreach (var item in b)
{
int value;
if (!dictionary.TryGetValue(item, out value))
{
return false;
}
if (value == 0)
{
return false;
}
dictionary[item] -= 1;
}
return dictionary.All(x => x.Value == 0);
}