C# 实例化具有运行时确定类型的对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/981330/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Instantiate an object with a runtime-determined type
提问by Odrade
I'm in a situation where I'd like to instantiate an object of a type that will be determined at runtime. I also need to perform an explicit cast to that type.
我想实例化一个将在运行时确定的类型的对象。我还需要对该类型执行显式转换。
Something like this:
像这样的东西:
static void castTest(myEnum val)
{
//Call a native function that returns a pointer to a structure
IntPtr = someNativeFunction(..params..);
//determine the type of the structure based on the enum value
Type structType = getTypeFromEnum(val);
structType myStruct = (structType)Marshal.PtrToStructure(IntPtr, structType);
}
This is obviously not valid code, but I hope it conveys the essence of what I'm trying to do. The method I'm actually working on will have to perform the marshaling operation on ~35 different types. I have several other methods that will need to do something similar with the same set of types. So, I'd like to isolate the type-determining logic from these methods so that I only need to write it once, and so that the methods stay clean and readable.
这显然不是有效的代码,但我希望它传达了我正在尝试做的事情的本质。我实际使用的方法必须对大约 35 种不同类型执行封送处理操作。我还有其他几种方法需要对同一组类型执行类似的操作。因此,我想将类型确定逻辑与这些方法隔离,以便我只需要编写一次,从而使方法保持干净和可读。
I must admit to being a total novice at design. Could anyone suggest a good approach to this problem? I suspect there might be an appropriate design pattern that I'm unaware of.
我必须承认我在设计方面完全是新手。任何人都可以提出解决这个问题的好方法吗?我怀疑可能存在我不知道的适当设计模式。
采纳答案by chakrit
There are several ways you can create an object of a certain type on the fly, one is:
有几种方法可以即时创建某种类型的对象,一种是:
// determine type here
var type = typeof(MyClass);
// create an object of the type
var obj = (MyClass)Activator.CreateInstance(type);
And you'll get an instance of MyClass in obj.
你会在 obj 中得到一个 MyClass 的实例。
Another way is to use reflection:
另一种方法是使用反射:
// get type information
var type = typeof(MyClass);
// get public constructors
var ctors = type.GetConstructors(BindingFlags.Public);
// invoke the first public constructor with no parameters.
var obj = ctors[0].Invoke(new object[] { });
And from one of ConstructorInfo returned, you can "Invoke()" it with arguments and get back an instance of the class as if you've used a "new" operator.
从返回的 ConstructorInfo 之一,您可以使用参数“Invoke()”它并返回类的实例,就像您使用了“new”运算符一样。
回答by Jason Punyon
I think you're looking for Activator.CreateInstance
我认为您正在寻找 Activator.CreateInstance
回答by Rex M
You can mostlydo what you're describing, but since you don't know the type at compile-time, you'll have to keep the instance loosely-typed; check its type at each point you use it, and cast it appropriately then (this will not be necessary with c# 4.0, which supports dynamics):
您基本上可以执行您所描述的操作,但是由于您在编译时不知道类型,因此您必须保持实例的松散类型;在您使用它的每个点检查它的类型,然后适当地转换它(这对于支持dynamics 的c# 4.0 没有必要):
Type type = CustomGetTypeMethod();
var obj = Activator.CreateInstance(type);
...
if(obj is MyCustomType)
{
((MyCustomType)obj).Property1;
}
else if (obj is MyOtherCustomType)
{
((MyOtherCustomType)obj).Property2;
}
回答by Aistina
Creating an instance of a run-time determined Type
is easy, using Activator.CreateInstance
, as others have mentioned. However, casting it, as you do in your example on the Marshal.PtrToStructure
line is not possible, as the type has to be known at compile time for casting. Also, note that Activator.CreateInstance
can not be used in conjunction with an IntPtr.
正如其他人提到的那样Type
,使用 来创建确定的运行时实例很容易Activator.CreateInstance
。但是,像您在示例中所做的那样进行转换Marshal.PtrToStructure
是不可能的,因为在编译时必须知道类型才能进行转换。另外,请注意Activator.CreateInstance
不能与 IntPtr 结合使用。
If your types have a common base class (other than Object
), you can cast it to said base type and call functions on that. Otherwise, calling functions will only be possible using reflection.
如果您的类型有一个公共基类(除了Object
),您可以将其转换为所述基类型并在其上调用函数。否则,只能使用反射来调用函数。
So either:
所以要么:
static void castTest(myEnum val)
{
//Call a native function that returns a pointer to a structure
IntPtr val = someNativeFunction(..params..);
//determine the type of the structure based on the enum value
Type structType = getTypeFromEnum(val);
BaseClass myStruct = (BaseClass)Marshal.PtrToStructure(IntPtr, structType);
myStruct.SomeFunctionDeclaredInBaseClass();
}
Or:
或者:
static void castTest(myEnum val)
{
//Call a native function that returns a pointer to a structure
IntPtr val = someNativeFunction(..params..);
//determine the type of the structure based on the enum value
Type structType = getTypeFromEnum(val);
object myStruct = Marshal.PtrToStructure(IntPtr, structType);
MemberInfo[] function = FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance,
(MemberFilter)delegate(MemberInfo info, object filter)
{
return info.Name == filter.ToString();
}, "SomeFunction");
if (mi.Length > 0 && mi[0] is MethodInfo)
((MethodInfo)mi[0]).Invoke(myStruct, ..params..);
}
回答by Jakob Flygare
You could go dynamic:
你可以动态:
using System;
namespace TypeCaster
{
class Program
{
internal static void Main(string[] args)
{
Parent p = new Parent() { name = "I am the parent", type = "TypeCaster.ChildA" };
dynamic a = Convert.ChangeType(new ChildA(p.name), Type.GetType(p.type));
Console.WriteLine(a.Name);
p.type = "TypeCaster.ChildB";
dynamic b = Convert.ChangeType(new ChildB(p.name), Type.GetType(p.type));
Console.WriteLine(b.Name);
}
}
internal class Parent
{
internal string type { get; set; }
internal string name { get; set; }
internal Parent() { }
}
internal class ChildA : Parent
{
internal ChildA(string name)
{
base.name = name + " in A";
}
public string Name
{
get { return base.name; }
}
}
internal class ChildB : Parent
{
internal ChildB(string name)
{
base.name = name + " in B";
}
public string Name
{
get { return base.name; }
}
}
}
回答by user5668312
methodName = NwSheet.Cells[rCnt1, cCnt1 - 2].Value2;
Type nameSpace=typeof(ReadExcel);
Type metdType = Type.GetType(nameSpace.Namespace + "." + methodName);
//ConstructorInfo magicConstructor = metdType.GetConstructor(Type.EmptyTypes);
//object magicClassObject = magicConstructor.Invoke(new object[] { });
object magicClassObject = Activator.CreateInstance(metdType);
MethodInfo mthInfo = metdType.GetMethod("fn_"+methodName);
StaticVariable.dtReadData.Clear();
for (iCnt = cCnt1 + 4; iCnt <= ShtRange.Columns.Count; iCnt++)
{
temp = NwSheet.Cells[1, iCnt].Value2;
StaticVariable.dtReadData.Add(temp.Trim(), Convert.ToString(NwSheet.Cells[rCnt1, iCnt].Value2));
}
//if (Convert.ToString(NwSheet.Cells[rCnt1, cCnt1 - 2].Value2) == "fn_AddNum" || Convert.ToString(NwSheet.Cells[rCnt1, cCnt1 - 2].Value2) == "fn_SubNum")
//{
// //StaticVariable.intParam1 = Convert.ToInt32(NwSheet.Cells[rCnt1, cCnt1 + 4].Value2);
// //StaticVariable.intParam2 = Convert.ToInt32(NwSheet.Cells[rCnt1, cCnt1 + 5].Value2);
// object[] mParam1 = new object[] { Convert.ToInt32(StaticVariable.dtReadData["InParam1"]), Convert.ToInt32(StaticVariable.dtReadData["InParam2"]) };
// object result = mthInfo.Invoke(this, mParam1);
// StaticVariable.intOutParam1 = Convert.ToInt32(result);
// NwSheet.Cells[rCnt1, cCnt1 + 2].Value2 = Convert.ToString(StaticVariable.intOutParam1) != "" ? Convert.ToString(StaticVariable.intOutParam1) : String.Empty;
//}
//else
//{
object[] mParam = new object[] { };
mthInfo.Invoke(magicClassObject, mParam);