以编程方式创建类似的 类 包括方法
Creating similiar classes programatically including methods
希望标题能解释我的问题,但我想做的是以编程方式创建 classes,但每个都有不同的属性以及每个特定的方法。
目前,每个 class 都是手动创建的,但如果可能的话,我想将其更改为以编程方式创建。目前,每个 class 将如下所示:
public class SomeEventName : EventBase
{
public string HardwareId { get; set; }
public ushort ComponantStatus { get; set; }
public override string ToString()
{
return string.Format("SomeEventName event - HardwareId: {0}, GeneratedTime: {1}, ReceivedTime: {2}", HardwareId , GeneratedTime, ReceivedTime);
}
public static SomeEventName Default(string tvmId, DateTime createTime, DateTime receiveTime)
{
return new SomeEventName
{
HardwareId = hardwareId,
GeneratedTime = generatedTime,
ReceivedTime = receivedTime,
AdaptedTime = DateTime.UtcNow
};
}
}
我已经替换了名字,但本质上是
SomeEventName
将是事件的名称
- 属性将特定于该事件
ToString
覆盖需要替换 SomeEventName
对于 class 的实际类型
Default
方法需要 return class 的一个实例。
我知道 classes 可以使用 Reflection.Emit
通过代码创建,但是在方法方面,我只看到通过 IL
代码实现的方法想避免。我可以更改 ToString
覆盖以使用参数来打印 class 类型,但我不确定如何处理 Default
方法。
必须具备的是我显然需要能够实例化所述 classes 并且我需要以下代码行来 return 实际类型而不是一些通用名称:
typeof(SomeEventName);
因此,Reflection
是我最好的选择吗?如果是,是否有一种方法可以处理 Default
方法而无需使用 IL
代码?还是有其他方法可以解决这个问题?
假设您想用给定的 类 编写程序集,您可以使用 runsharp。一旦掌握了语法,就可以在运行时编写程序集,供其他应用程序引用。
声明非常简单,您可以使用它来编写有效的 .NET 程序集(具有可反射的 .NET 代码)而无需处理 IL。
如果您使用的是 C# 6,则可以使用 Roslyn 服务即时编译 C#。例如参见 [=10=].
所以我有一种方法可以通过使用泛型来实现我所需要的,并从答案中得到帮助 - Dynamically create a class in C#
第一件事是将 SomeEventName
转换为使用泛型,这样我就可以将其用作基础 class。 GetType()
这样我就可以区分可以创建的每种类型。这给了我:
public class EventBase
{
public string HardwareId { get;set; }
public DateTime MessageGeneratedTime { get; set; }
public DateTime MessageReceivedTime { get; set; }
public DateTime MessageAdaptedTime { get; set; }
public override string ToString()
{
return string.Format("{0} event - HardwareId: {1}, CreateTime: {2}, MessageReceivedTime: {3}", GetType(), HardwareId, MessageGeneratedTime, MessageReceivedTime);
}
public T Default<T>(string dardwareId, DateTime createTime, DateTime receiveTime) where T : TestBase, new()
{
var instance = new T
{
HardwareId = hardwareId,
MessageGeneratedTime = createTime,
MessageReceivedTime = receiveTime,
MessageAdaptedTime = DateTime.UtcNow
};
return instance;
}
}
接下来我需要实例化每种类型。我从一个开始,但我可以很容易地扩展我必须创建的其他类型。所以在上面链接的答案的帮助下,我得到了:
var myType = CompileResultType(properties);
var myObject = Activator.CreateInstance(myType);
虽然我不会包含该答案中的所有代码,但关键是:
private static TypeBuilder GetTypeBuilder()
{
var typeSignature = "SomeEventName";
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("TypeOfTest");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
typeof(TestBase),
null);
return tb;
}
在该代码中,我创建了 SomeEventName
的签名并将其作为我的基础 class、EventBase
。
一旦我有了 type
和 object
,我就可以给它传递一些参数并调用基础 class 中的 Default
方法,同时使它成为通用的.
var arguements = new object[] { "QWERTY", DateTime.UtcNow, DateTime.UtcNow };
var @event = myObject.GetType().GetMethod("Default").MakeGenericMethod(myObject.GetType()).Invoke(myObject, arguements);
因为这是在控制台应用程序中,所以我可以调用我的 ToString
覆盖,它基于上面代码中的参数,给出输出:
SomeEventName event - Device: QWERTY, CreateTime: 05/10/2015 15:18:25,
MessageReceivedTime: 05/10/2015 15:18:25
另一个要求是我可以创建属性,在上面的代码中,您可以看到我调用 CompileResultType
传递参数列表。所以我所做的就是:
var properties = new Dictionary<string, string>();
properties.Add("Field1", "System.String");
properties.Add("Field2", "System.Int32");
然后我当然可以设置它们的值:
myObject.GetType().GetProperty("Field1").SetValue(myObject, "Hello world");
myObject.GetType().GetProperty("Field2").SetValue(myObject, 987);
然后将它们输出到控制台window:
Console.WriteLine("Field1: {0}", myObject.GetType().GetProperty("Field1").GetValue(myObject));
Console.WriteLine("Field2: {0}", myObject.GetType().GetProperty("Field2").GetValue(myObject));
虽然它可能不是最好的解决方案,而且它确实有缺点,例如一切都变成字符串,但它可以满足要求。如前所述,这仅适用于一种类型,但可以通过将 signature
作为字符串传递给 CompileResultType
进而将其传递给 GetTypeBuilder
.[=31= 来轻松扩展它]
希望标题能解释我的问题,但我想做的是以编程方式创建 classes,但每个都有不同的属性以及每个特定的方法。
目前,每个 class 都是手动创建的,但如果可能的话,我想将其更改为以编程方式创建。目前,每个 class 将如下所示:
public class SomeEventName : EventBase
{
public string HardwareId { get; set; }
public ushort ComponantStatus { get; set; }
public override string ToString()
{
return string.Format("SomeEventName event - HardwareId: {0}, GeneratedTime: {1}, ReceivedTime: {2}", HardwareId , GeneratedTime, ReceivedTime);
}
public static SomeEventName Default(string tvmId, DateTime createTime, DateTime receiveTime)
{
return new SomeEventName
{
HardwareId = hardwareId,
GeneratedTime = generatedTime,
ReceivedTime = receivedTime,
AdaptedTime = DateTime.UtcNow
};
}
}
我已经替换了名字,但本质上是
SomeEventName
将是事件的名称- 属性将特定于该事件
ToString
覆盖需要替换SomeEventName
对于 class 的实际类型
Default
方法需要 return class 的一个实例。
我知道 classes 可以使用 Reflection.Emit
通过代码创建,但是在方法方面,我只看到通过 IL
代码实现的方法想避免。我可以更改 ToString
覆盖以使用参数来打印 class 类型,但我不确定如何处理 Default
方法。
必须具备的是我显然需要能够实例化所述 classes 并且我需要以下代码行来 return 实际类型而不是一些通用名称:
typeof(SomeEventName);
因此,Reflection
是我最好的选择吗?如果是,是否有一种方法可以处理 Default
方法而无需使用 IL
代码?还是有其他方法可以解决这个问题?
假设您想用给定的 类 编写程序集,您可以使用 runsharp。一旦掌握了语法,就可以在运行时编写程序集,供其他应用程序引用。
声明非常简单,您可以使用它来编写有效的 .NET 程序集(具有可反射的 .NET 代码)而无需处理 IL。
如果您使用的是 C# 6,则可以使用 Roslyn 服务即时编译 C#。例如参见 [=10=].
所以我有一种方法可以通过使用泛型来实现我所需要的,并从答案中得到帮助 - Dynamically create a class in C#
第一件事是将 SomeEventName
转换为使用泛型,这样我就可以将其用作基础 class。 GetType()
这样我就可以区分可以创建的每种类型。这给了我:
public class EventBase
{
public string HardwareId { get;set; }
public DateTime MessageGeneratedTime { get; set; }
public DateTime MessageReceivedTime { get; set; }
public DateTime MessageAdaptedTime { get; set; }
public override string ToString()
{
return string.Format("{0} event - HardwareId: {1}, CreateTime: {2}, MessageReceivedTime: {3}", GetType(), HardwareId, MessageGeneratedTime, MessageReceivedTime);
}
public T Default<T>(string dardwareId, DateTime createTime, DateTime receiveTime) where T : TestBase, new()
{
var instance = new T
{
HardwareId = hardwareId,
MessageGeneratedTime = createTime,
MessageReceivedTime = receiveTime,
MessageAdaptedTime = DateTime.UtcNow
};
return instance;
}
}
接下来我需要实例化每种类型。我从一个开始,但我可以很容易地扩展我必须创建的其他类型。所以在上面链接的答案的帮助下,我得到了:
var myType = CompileResultType(properties);
var myObject = Activator.CreateInstance(myType);
虽然我不会包含该答案中的所有代码,但关键是:
private static TypeBuilder GetTypeBuilder()
{
var typeSignature = "SomeEventName";
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("TypeOfTest");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
typeof(TestBase),
null);
return tb;
}
在该代码中,我创建了 SomeEventName
的签名并将其作为我的基础 class、EventBase
。
一旦我有了 type
和 object
,我就可以给它传递一些参数并调用基础 class 中的 Default
方法,同时使它成为通用的.
var arguements = new object[] { "QWERTY", DateTime.UtcNow, DateTime.UtcNow };
var @event = myObject.GetType().GetMethod("Default").MakeGenericMethod(myObject.GetType()).Invoke(myObject, arguements);
因为这是在控制台应用程序中,所以我可以调用我的 ToString
覆盖,它基于上面代码中的参数,给出输出:
SomeEventName event - Device: QWERTY, CreateTime: 05/10/2015 15:18:25, MessageReceivedTime: 05/10/2015 15:18:25
另一个要求是我可以创建属性,在上面的代码中,您可以看到我调用 CompileResultType
传递参数列表。所以我所做的就是:
var properties = new Dictionary<string, string>();
properties.Add("Field1", "System.String");
properties.Add("Field2", "System.Int32");
然后我当然可以设置它们的值:
myObject.GetType().GetProperty("Field1").SetValue(myObject, "Hello world");
myObject.GetType().GetProperty("Field2").SetValue(myObject, 987);
然后将它们输出到控制台window:
Console.WriteLine("Field1: {0}", myObject.GetType().GetProperty("Field1").GetValue(myObject));
Console.WriteLine("Field2: {0}", myObject.GetType().GetProperty("Field2").GetValue(myObject));
虽然它可能不是最好的解决方案,而且它确实有缺点,例如一切都变成字符串,但它可以满足要求。如前所述,这仅适用于一种类型,但可以通过将 signature
作为字符串传递给 CompileResultType
进而将其传递给 GetTypeBuilder
.[=31= 来轻松扩展它]