동적 클래스를 많이 사용하지 않고 방출하고 벽돌 벽에 머리를 대고 있습니다. 내가 원하는 것은 구조체와 다른 값 유형을 관리되는 메모리와 기본 메모리로 이동할 때 사용할 수있는 도우미입니다.TypeBuilder 및 Emit을 통해 구현할 때 인터페이스 서명을 올바르게 가져올 수 없습니다.
나는 일반적으로 생각했다.하지만 정의한 인터페이스를 제대로 지원하려면 생성 유형을 얻을 수 없다. 마지막으로 TypeBuilder.CreateType()을 호출 할 때마다 형식이 인터페이스의 두 메서드 중 첫 번째를 구현하지 못한다는 예외를 throw합니다. 두 번째 메서드도 지원하지 않는다고 생각하지만, 그렇지 않습니다. 그걸 멀리 가져와. DefineGenericParameters를 사용하거나 사용하지 않고 수행했습니다. 대신 실제 유형을 전달합니다. 예를 들어, byte * 매개 변수와 같이 많은 변형을 시도했습니다. 나는 그것을 쓸 수없는 값 유형이라고 말하는 일반 매개 변수를 지정하려고했습니다. 여기 방출과 인터페이스에 대한 다른 질문을 살펴 보았습니다. 그런 질문이 무엇을 의미하는지 생각해 봤습니다.
간단한 조정이 필요한지, 아니면 기본적으로 누락 된 항목이 있는지 알 수 없습니다.
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace Testing
{
class Program
{
static unsafe void Main(string[] args)
{
NativeValueAccessFactory factory = new NativeValueAccessFactory();
INativeValueAccessor<XTestStruct> caller = (INativeValueAccessor<XTestStruct>)factory.GetNativeValueAccessor<XTestStruct>();
byte[] buffer = new byte[1024];
XTestStruct item1 = new XTestStruct(1000, 2000);
fixed (byte* pBuffer = &buffer[0])
{
caller.WriteData(item1, pBuffer);
}
XTestStruct item2 = new XTestStruct(1, 1);
fixed (byte* pBuffer = &buffer[0])
{
item2 = caller.ReadData(pBuffer);
}
// Compare item1 and item2
}
}
public struct XTestStruct
{
public int i;
public int j;
public XTestStruct(int i, int j) { this.i = i; this.j = j; }
}
public unsafe interface INativeValueAccessor<T> where T : struct
{
T ReadData(byte* data);
void WriteData(T item, byte* data);
}
public class NativeValueAccessFactory
{
public NativeValueAccessFactory() { }
public object GetNativeValueAccessor<T>() where T : struct
{
Type itemType = typeof(T);
var rand = new Random();
var name = string.Format("{0}_{1}", itemType.Name, rand.Next());
var assemblyName = new AssemblyName(name);
var assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(name + ".dll");
TypeBuilder typeBuilder = moduleBuilder.DefineType(name, TypeAttributes.Public);
typeBuilder.AddInterfaceImplementation(typeof(INativeValueAccessor<T>));
// ReadData method
MethodBuilder methodBuilder1 = typeBuilder.DefineMethod("ReadData", MethodAttributes.Public | MethodAttributes.Virtual);
GenericTypeParameterBuilder[] generics1 = methodBuilder1.DefineGenericParameters("T");
generics1[0].SetGenericParameterAttributes(GenericParameterAttributes.NotNullableValueTypeConstraint);
methodBuilder1.SetReturnType(generics1[0]);
methodBuilder1.SetParameters(typeof(byte*)); // also tried typeof(byte).MakeByRefType()
ILGenerator codeGen1 = methodBuilder1.GetILGenerator();
codeGen1.Emit(OpCodes.Ldarg_1);
codeGen1.Emit(OpCodes.Ldobj, itemType);
codeGen1.Emit(OpCodes.Ret);
// WriteData method
MethodBuilder methodBuilder2 = typeBuilder.DefineMethod("WriteData", MethodAttributes.Public | MethodAttributes.Virtual);
GenericTypeParameterBuilder[] generics2 = methodBuilder2.DefineGenericParameters("T");
generics2[0].SetGenericParameterAttributes(GenericParameterAttributes.NotNullableValueTypeConstraint);
methodBuilder2.SetReturnType(null);
methodBuilder2.SetParameters(generics2[0], typeof(byte*));
ILGenerator codeGen2 = methodBuilder2.GetILGenerator();
codeGen2.Emit(OpCodes.Ldarg_2);
codeGen2.Emit(OpCodes.Ldarg_1);
codeGen2.Emit(OpCodes.Stobj, itemType);
codeGen2.Emit(OpCodes.Ret);
Type generatedType = typeBuilder.CreateType(); // Throws exception here saying interface not implemented
return Activator.CreateInstance(generatedType); // not at all confident this will work, but not even getting here
}
}
}
I 관리 및 기본 메모리 사이의 구조체를 복사 할 수있는 다른 방법을 많이 알고,하지만 그들 중 대부분은 어느 클래스의 사용자에게 대량으로 느린 (예 : BinaryReader를, Marshal.PtrToStructure) 또는 불편 (필요 복사본을 수행하는 대표자를 제공하는 것 등). 동적 인 방법으로이 작업을 수행 할 수 있는지 정말보고 싶었습니다. 내가 잘못하고있는 작업을 파악할 수 있다면 가능한 것처럼 보입니다.
작년에 emit 라이브러리를 만들 때, 고도로 튜닝 된 (예 : IL에서 최적화 될 수있는) C#으로 샘플 메서드를 작성한 다음 ILSpy에서 코드를 본 다음 추가로 튜닝했지만 일리노이의 95 %를 줘. – SledgeHammer
사실 일리노이가 괜찮다고 생각합니다. 적어도, 그것이 틀렸다면 나는 충분히 확인할 수 없다. 그러나 아마 C#에서 도덕적으로 상응하는 것을 쓸 수 있습니다. 그런 다음 ILSpy가 서명에 대한 단서를 제공하는지 확인하십시오. – BruceCo
제네릭 기본 클래스를 만들어 구현하지 않으면 많은 문제를 예방할 수 있습니다. – Nikolaus