![](/img/trans.png)
[英]Activator.CreateInstance calling constructor but returning null
[英]Activator.CreateInstance calling constructor with class as parameter
嗨,我正在嘗試動態地執行以下操作,我正在使用自己的CreateInstance方法,但是已經通過Activator.CreateInstance測試過
IPEndPoint newObject = new IPEndPoint(IPAddress.Any, 80);
當我嘗試使用激活器時出現錯誤,無法將System.RuntimeType轉換為IPAddress
public static object CreateInstance(Type context, object[] Params)
{
List<Type> argTypes = new List<Type>();
foreach (object Param in Params)
argTypes.Add(GetType(Param));
ConstructorInfo[] Types = context.GetConstructors();
foreach (ConstructorInfo node in Types)
{
ParameterInfo[] Args = node.GetParameters();
if (Params.Length == Args.Length)
{
bool[] cond = new bool[Params.Length];
for (int i = 0; i < Params.Length; i++)
if (argTypes[i] == Args[i].ParameterType) cond[i] = true;
if (cond[0] == true & cond[1] == true)
return node.Invoke(Params);
}
}
return null;
}
這就是參數在數組[0] {Name =“ IPAddress” FullName =“ System.Net.IPAddress”}中的樣子[1] 80
這是調用代碼,prob應該已經提供了它,所以您知道我要嘗試執行的操作,因為您可以看到它解析表示類的字符串值,這就是為什么我不能使用typeof或typeconstraints的原因。
private object CreateInstance(ObjectCreationExpression Exp)
{
object context = GetContext(Exp.Identifier); //Gets the class type
Type t = (Type)context;
object[] Params = GetParams(Exp.ArgumentList).ToArray();
object newObject = Activator.CreateInstance(t, Params);
return newObject;
}
public static object GetContext(string classname)
{
return ParseNamespace("System.dll", classname);
}
private static object ParseNamespace(string Namespace, string classname) //Looks up class in System.dll
{
string DotNetPath = ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.VersionLatest);
Assembly Asm = Assembly.LoadFile(DotNetPath + @"\" + Namespace);
Type[] Types = Asm.GetExportedTypes();
foreach (Type Node in Types)
{
if (Node.Name == classname)
return Node;
}
return null;
}
private List<object> GetParams(NodeCollection<ArgumentNode> Params)
{
List<object> Arguments = new List<object>();
foreach (ArgumentNode node in Params)
{
if (node.Expression is MemberAccessExpression)
{
MemberAccessExpression exp = (MemberAccessExpression)node.Expression;
Type value = (Type)GetContext(exp);
string name = DirectCast<IdentifierExpression>(exp.Right).Identifier;
if (value.IsEnum)
{
string[] names = DirectCast<Type>(value).GetEnumNames();
Array item = DirectCast<Type>(value).GetEnumValues();
Arguments.Add(item.GetValue(names.ToList().IndexOf(name)));
}
else
{
Type item = value.GetMember(name)[0].ReflectedType;
Arguments.Add(item);
}
}
else
Arguments.Add((Int32)ParseType(node.Expression));
}
return Arguments;
}
ObjectCreationExpression是一個自定義類,其中包含用於創建新實例的已解析源代碼,兩個主要屬性是ArgumentList,它是用作參數的值或標識符的集合,另一個屬性是我們正在創建的類型的標識符
您已經編寫了一個不錯的實現來創建對象實例,但是它存在一些缺陷。 我已經在下面的代碼中更正了它們
public static object CreateInstance(Type context, params object[] Params) // params keyword for array
{
List<Type> argTypes = new List<Type>();
//used .GetType() method to get the appropriate type
//Param can be null so handle accordingly
foreach (object Param in Params)
argTypes.Add((Param ?? new object()).GetType());
ConstructorInfo[] Types = context.GetConstructors();
foreach (ConstructorInfo node in Types)
{
ParameterInfo[] Args = node.GetParameters();
if (Params.Length == Args.Length)
{
bool[] cond = new bool[Params.Length];
//handle derived types
for (int i = 0; i < Params.Length; i++)
if (Args[i].ParameterType.IsAssignableFrom(argTypes[i])) cond[i] = true;
if (cond[0] && cond[1])
return node.Invoke(Params);
}
}
return null;
}
呼叫碼
IPEndPoint newObject = (IPEndPoint)CreateInstance(typeof(IPEndPoint), IPAddress.Any, 80);
注意我可能無法糾正上面示例中的每個缺陷,只是使它適用於您的情況,即您調用代碼
泛型實現
public static T CreateInstance<T>(params object[] Params) where T : class // params keyword for array
{
List<Type> argTypes = new List<Type>();
//used .GetType() method to get the appropriate type
//Param can be null so handle accordingly
foreach (object Param in Params)
argTypes.Add((Param ?? new object()).GetType());
ConstructorInfo[] Types = typeof(T).GetConstructors();
foreach (ConstructorInfo node in Types)
{
ParameterInfo[] Args = node.GetParameters();
if (Params.Length == Args.Length)
{
bool[] cond = new bool[Params.Length];
//handle derived types
for (int i = 0; i < Params.Length; i++)
if (Args[i].ParameterType.IsAssignableFrom(argTypes[i])) cond[i] = true;
if (cond[0] && cond[1])
return (T)node.Invoke(Params);
}
}
return default(T);
}
呼叫碼
IPEndPoint newObject = CreateInstance<IPEndPoint>(IPAddress.Any, 80);
完全動態的對象構造
public static object CreateInstance(Type pContext, object[] Params)
{
List<Type> argTypes = new List<Type>();
//used .GetType() method to get the appropriate type
//Param can be null so handle accordingly
if (Params != null)
foreach (object Param in Params)
{
if (Param != null)
argTypes.Add(Param.GetType());
else
argTypes.Add(null);
}
ConstructorInfo[] Types = pContext.GetConstructors();
foreach (ConstructorInfo node in Types)
{
ParameterInfo[] Args = node.GetParameters();
// Params can be null for default constructors so use argTypes
if (argTypes.Count == Args.Length)
{
bool areTypesCompatible = true;
for (int i = 0; i < Params.Length; i++)
{
if (argTypes[i] == null)
{
if (Args[i].ParameterType.IsValueType)
{
//fill the defaults for value type if not supplied
Params[i] = CreateInstance(Args[i].ParameterType, null);
argTypes[i] = Params[i].GetType();
}
else
{
argTypes[i] = Args[i].ParameterType;
}
}
if (!Args[i].ParameterType.IsAssignableFrom(argTypes[i]))
{
areTypesCompatible = false;
break;
}
}
if (areTypesCompatible)
return node.Invoke(Params);
}
}
//delegate type to Activator.CreateInstance if unable to find a suitable constructor
return Activator.CreateInstance(pContext);
}
呼叫碼
IPEndPoint newObject = (IPEndPoint)CreateInstance(typeof(IPEndPoint), new object[] { IPAddress.Any, 80});
此代碼還可以將參數設為空
例如
IPEndPoint newObject = (IPEndPoint)CreateInstance(typeof(IPEndPoint), new object[] { IPAddress.Any, null});
我對其進行了簡化,還為默認構造函數處理了空參數。 和其他幾張支票
因此,即使您也可以construct value types
,此更改也使其完全動態
例如
int obj = (int)CreateInstance(typeof(int), null);
您的案例
object context = GetContext(Exp.Identifier);
Type t = (Type)context;
object[] Params = GetParams(Exp.ArgumentList).ToArray();
//use the above defined method and it will work as expected
object newObject = CreateInstance(t, Params);
對於它的價值,這是我對您的方法的重構:
public static object CreateInstance(Type pContext, params object[] pArguments) {
var constructors = pContext.GetConstructors();
foreach (var constructor in constructors) {
var parameters = constructor.GetParameters();
if (parameters.Length != pArguments.Length)
continue;
// assumed you wanted a matching constructor
// not just one that matches the first two types
bool fail = false;
for (int x = 0; x < parameters.Length && !fail; x++)
if (!parameters[x].ParameterType.IsInstanceOfType(pArguments[x]))
fail = true;
if (!fail)
return constructor.Invoke(pArguments);
}
return null;
}
請注意,您似乎反過來具有“參數”和“參數”的概念。 “參數”是接受值的方法的命名部分。 “參數”是您傳遞的實際值。
除此之外,聽起來您的問題更多地與傳遞的值有關,而不是方法的實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.