Создание экземпляра объекта с типом, определенным во время выполнения
Я нахожусь в ситуации, когда я хотел бы создать экземпляр объекта типа, который будет определен во время выполнения. Мне также нужно выполнить явное приведение к этому типу.
что-то вроде этого:
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);
}
это явно неверный код, но я надеюсь, что он передает суть того, что я пытаюсь сделать. Метод, над которым я фактически работаю, должен будет выполнить операцию маршалинга на ~35 различных типах. У меня есть несколько других методов, которые нужно будет сделать что-то аналогично с тем же набором типов. Итак, я хотел бы изолировать логику определения типа от этих методов, чтобы мне нужно было написать ее только один раз, и чтобы методы оставались чистыми и читаемыми.
Я должен признать, что я полный новичок в дизайне. Может ли кто-нибудь предложить хороший подход к этой проблеме? Я подозреваю, что может быть соответствующий шаблон дизайна, о котором я не знаю.
6 ответов:
есть несколько способов создать объект определенного типа на лету, один из них:
// determine type here var type = typeof(MyClass); // create an object of the type var obj = (MyClass)Activator.CreateInstance(type);
и вы получите экземпляр MyClass в obj.
другой способ-использовать отражение:
// 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[] { });
и из одного из возвращенных ConstructorInfo вы можете " вызвать () "его с аргументами и вернуть экземпляр класса, как если бы вы использовали оператор" new".
вы можете в основном делайте то, что вы описываете, но поскольку вы не знаете тип во время компиляции, вам придется сохранить экземпляр слабо типизированным; проверьте его тип в каждой точке, которую вы используете, и приведите его соответствующим образом (это не будет необходимо с 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; }
создание экземпляра определенного времени выполнения
Type
легко, используяActivator.CreateInstance
, как отметили другие. Однако, бросая его, как вы делаете в вашем примере наMarshal.PtrToStructure
строка невозможна, так как тип должен быть известен во время компиляции для приведения. Кроме того, обратите внимание, чтоActivator.CreateInstance
не может использоваться в сочетании с IntPtr.если типы имеют общий базовый класс (кроме
Object
), вы можете привести его к указанному базовому типу и вызвать функции на этом. В противном случае, вызов функции будут возможны только с помощью отражения.следующим образом:
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(); }
или:
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..); }
вы можете пойти динамический:
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; } } } }
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);