forked from cheungt6/public
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
472 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Application x:Class="ReflectionEmitClassGeneration.App" | ||
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" | ||
StartupUri="View/MainWindow.xaml"> | ||
<Application.Resources> | ||
|
||
|
||
</Application.Resources> | ||
</Application> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Configuration; | ||
using System.Data; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using System.Windows; | ||
|
||
namespace ReflectionEmitClassGeneration | ||
{ | ||
/// <summary> | ||
/// Interaction logic for App.xaml | ||
/// </summary> | ||
public partial class App : Application | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System; | ||
using System.Windows.Input; | ||
|
||
namespace ReflectionEmitClassGeneration.Command | ||
{ | ||
public abstract class CommandBase : ICommand | ||
{ | ||
public virtual bool CanExecute(object parameter) | ||
{ | ||
return true; | ||
} | ||
|
||
public abstract void Execute(object parameter); | ||
|
||
public event EventHandler CanExecuteChanged | ||
{ | ||
add { CommandManager.RequerySuggested += value; } | ||
remove { CommandManager.RequerySuggested -= value; } | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
using System; | ||
|
||
namespace ReflectionEmitClassGeneration.Command | ||
{ | ||
public class GenericCommand : CommandBase | ||
{ | ||
private readonly Action _commandAction; | ||
private readonly Func<object, bool> _canExecute; | ||
|
||
public GenericCommand(Action commandAction) | ||
{ | ||
_commandAction = commandAction; | ||
} | ||
|
||
public GenericCommand(Action commandAction, Func<object, bool> canExecute) : this(commandAction) | ||
{ | ||
_canExecute = canExecute; | ||
} | ||
|
||
public override void Execute(object parameter) | ||
{ | ||
_commandAction.Invoke(); | ||
} | ||
|
||
public override bool CanExecute(object obj) | ||
{ | ||
var result = ((_canExecute == null) || | ||
(_canExecute != null && _canExecute(obj))) && | ||
|
||
base.CanExecute(obj); | ||
|
||
return result; | ||
} | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
ReflectionEmitClassGeneration/ReflectionEmitClassGeneration.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> | ||
|
||
<PropertyGroup> | ||
<OutputType>WinExe</OutputType> | ||
<TargetFramework>netcoreapp3.0</TargetFramework> | ||
<UseWPF>true</UseWPF> | ||
</PropertyGroup> | ||
|
||
</Project> |
25 changes: 25 additions & 0 deletions
25
ReflectionEmitClassGeneration/ReflectionEmitClassGeneration.sln
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 16 | ||
VisualStudioVersion = 16.0.29411.108 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReflectionEmitClassGeneration", "ReflectionEmitClassGeneration.csproj", "{18A83D6A-D546-46A7-9D11-93B003A4F020}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{18A83D6A-D546-46A7-9D11-93B003A4F020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{18A83D6A-D546-46A7-9D11-93B003A4F020}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{18A83D6A-D546-46A7-9D11-93B003A4F020}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{18A83D6A-D546-46A7-9D11-93B003A4F020}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {A5A37B24-EFC6-4FD1-AB09-7E3DF817341F} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Reflection; | ||
using System.Reflection.Emit; | ||
|
||
namespace ReflectionEmitClassGeneration.Types | ||
{ | ||
public class TypeGenerator : TypeGeneratorGeneric<object> | ||
{ | ||
public TypeGenerator(Dictionary<string, Type> properties) : base(properties) | ||
{ | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Generate a new type that uses T as the base class | ||
/// </summary> | ||
/// <typeparam name="T"></typeparam> | ||
public class TypeGeneratorGeneric<T> where T : class | ||
{ | ||
private readonly Dictionary<string, MethodInfo> _setMethods; | ||
|
||
public TypeGeneratorGeneric(Dictionary<string, Type> properties) | ||
{ | ||
Properties = properties; | ||
_setMethods = new Dictionary<string, MethodInfo>(); | ||
Initialise(); | ||
} | ||
|
||
private void Initialise() | ||
{ | ||
var newTypeName = Guid.NewGuid().ToString(); | ||
var assemblyName = new AssemblyName(newTypeName); | ||
var dynamicAssembly = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); | ||
var dynamicModule = dynamicAssembly.DefineDynamicModule("Main"); | ||
var dynamicType = dynamicModule.DefineType(newTypeName, | ||
TypeAttributes.Public | | ||
TypeAttributes.Class | | ||
TypeAttributes.AutoClass | | ||
TypeAttributes.AnsiClass | | ||
TypeAttributes.BeforeFieldInit | | ||
TypeAttributes.AutoLayout, | ||
typeof(T)); | ||
dynamicType.DefineDefaultConstructor(MethodAttributes.Public | | ||
MethodAttributes.SpecialName | | ||
MethodAttributes.RTSpecialName); | ||
|
||
foreach (var property in Properties) | ||
AddProperty(dynamicType, property.Key, property.Value); | ||
|
||
GeneratedType = dynamicType.CreateType(); | ||
|
||
foreach (var property in Properties) | ||
{ | ||
var propertyInfo = GeneratedType.GetProperty(property.Key); | ||
|
||
var setMethod = propertyInfo.GetSetMethod(); | ||
if (setMethod == null) continue; | ||
_setMethods.Add(property.Key, setMethod); | ||
} | ||
} | ||
|
||
public Type GeneratedType { private set; get; } | ||
|
||
public Dictionary<string, Type> Properties { get; } | ||
|
||
private static void AddProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType) | ||
{ | ||
var fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private); | ||
var propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null); | ||
|
||
var getMethod = typeBuilder.DefineMethod("get_" + propertyName, | ||
MethodAttributes.Public | | ||
MethodAttributes.SpecialName | | ||
MethodAttributes.HideBySig, propertyType, Type.EmptyTypes); | ||
var getMethodIL = getMethod.GetILGenerator(); | ||
getMethodIL.Emit(OpCodes.Ldarg_0); | ||
getMethodIL.Emit(OpCodes.Ldfld, fieldBuilder); | ||
getMethodIL.Emit(OpCodes.Ret); | ||
|
||
var setMethod = typeBuilder.DefineMethod("set_" + propertyName, | ||
MethodAttributes.Public | | ||
MethodAttributes.SpecialName | | ||
MethodAttributes.HideBySig, | ||
null, new[] { propertyType }); | ||
var setMethodIL = setMethod.GetILGenerator(); | ||
Label modifyProperty = setMethodIL.DefineLabel(); | ||
Label exitSet = setMethodIL.DefineLabel(); | ||
|
||
setMethodIL.MarkLabel(modifyProperty); | ||
setMethodIL.Emit(OpCodes.Ldarg_0); | ||
setMethodIL.Emit(OpCodes.Ldarg_1); | ||
setMethodIL.Emit(OpCodes.Stfld, fieldBuilder); | ||
|
||
setMethodIL.Emit(OpCodes.Nop); | ||
setMethodIL.MarkLabel(exitSet); | ||
setMethodIL.Emit(OpCodes.Ret); | ||
|
||
propertyBuilder.SetGetMethod(getMethod); | ||
propertyBuilder.SetSetMethod(setMethod); | ||
} | ||
|
||
/// <summary> | ||
/// Create a new instance of your generated type | ||
/// </summary> | ||
/// <typeparam name="T"></typeparam> | ||
/// <param name="values"></param> | ||
/// <returns></returns> | ||
public T CreateInstance(Dictionary<string, object> values = null) | ||
{ | ||
var instance = (T)Activator.CreateInstance(GeneratedType); | ||
|
||
if (values != null) | ||
SetValues(instance, values); | ||
|
||
return instance; | ||
} | ||
|
||
/// <summary> | ||
/// Update the property values on an instance of your generated type | ||
/// </summary> | ||
/// <typeparam name="T"></typeparam> | ||
/// <param name="instance"></param> | ||
/// <param name="values"></param> | ||
public void SetValues(T instance, Dictionary<string, object> values) | ||
{ | ||
foreach (var value in values) | ||
SetValue(instance, value.Key, value.Value); | ||
} | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <typeparam name="T"></typeparam> | ||
/// <param name="instance"></param> | ||
/// <param name="propertyName"></param> | ||
/// <param name="propertyValue"></param> | ||
public void SetValue(T instance, string propertyName, object propertyValue) | ||
{ | ||
if (!_setMethods.TryGetValue(propertyName, out var setter)) | ||
throw new ArgumentException($"Type does not contain settter for property {propertyName}", nameof(propertyName)); | ||
setter.Invoke(instance, new[] { propertyValue }); | ||
} | ||
|
||
/// <summary> | ||
/// Create a new list of your new type and populate on initialisation | ||
/// </summary> | ||
/// <param name="values"></param> | ||
/// <returns></returns> | ||
public IList CreateList(T [] values = null) | ||
{ | ||
var listGenericType = typeof(List<>); | ||
var list = listGenericType.MakeGenericType(GeneratedType); | ||
var constructor = list.GetConstructor(new Type[] { }); | ||
var newList = (IList)constructor.Invoke(new object[] { }); | ||
foreach (var value in values) | ||
newList.Add(value); | ||
return newList; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
|
||
namespace ReflectionEmitClassGeneration.Types | ||
{ | ||
public static class TypeHelper | ||
{ | ||
public static Dictionary<string, Type> GetPublicProperties(System.Collections.IEnumerable itemSource) | ||
{ | ||
var type = itemSource.GetType().GetTypeInfo(); | ||
var publicProperties = type.GetProperties(BindingFlags.Public); | ||
var propertiesDict = publicProperties.ToDictionary(k => k.Name, v => v.PropertyType); | ||
return propertiesDict; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<Window x:Class="ReflectionEmitClassGeneration.View.MainWindow" | ||
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:d="https://schemas.microsoft.com/expression/blend/2008" | ||
xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" | ||
xmlns:viewmodel="clr-namespace:ReflectionEmitClassGeneration.ViewModel" | ||
mc:Ignorable="d" | ||
Title="ReflectionEmitClassGeneration" Height="450" Width="800"> | ||
<Window.DataContext> | ||
<viewmodel:MainWindowViewModel/> | ||
</Window.DataContext> | ||
<Grid> | ||
<Grid.RowDefinitions> | ||
<RowDefinition Height="*"/> | ||
<RowDefinition Height="35"/> | ||
<RowDefinition Height="35"/> | ||
</Grid.RowDefinitions> | ||
<Grid.ColumnDefinitions> | ||
<ColumnDefinition/> | ||
<ColumnDefinition/> | ||
</Grid.ColumnDefinitions> | ||
<DataGrid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5,5,5" ItemsSource="{Binding Items, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" | ||
CanUserAddRows="False" CanUserDeleteRows="False" ColumnWidth="*" GridLinesVisibility="All"> | ||
</DataGrid> | ||
|
||
<TextBox Grid.Row="1" Grid.Column="0" Text="{Binding NewPropertyName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ></TextBox> | ||
<Button Grid.Row="1" Grid.Column="1" Command="{Binding GenerateItemCommand}" CommandParameter="{Binding NewPropertyName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">Add Property</Button> | ||
</Grid> | ||
</Window> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using ReflectionEmitClassGeneration.ViewModel; | ||
using System.Collections.ObjectModel; | ||
using System.ComponentModel; | ||
using System.Windows; | ||
|
||
namespace ReflectionEmitClassGeneration.View | ||
{ | ||
/// <summary> | ||
/// Interaction logic for MainWindow.xaml | ||
/// </summary> | ||
public partial class MainWindow : Window | ||
{ | ||
public MainWindow() | ||
{ | ||
InitializeComponent(); | ||
|
||
} | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
ReflectionEmitClassGeneration/ViewModel/ItemViewModelBase.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
|
||
namespace ReflectionEmitClassGeneration.ViewModel | ||
{ | ||
public class ItemViewModelBase: ViewModelBase | ||
{ | ||
public ItemViewModelBase() | ||
{ | ||
|
||
} | ||
} | ||
} |
Oops, something went wrong.