C#에서 익명 개체의 속성을 어떻게 반복합니까?
익명 개체를 메서드에 대한 인수로 사용하고 해당 속성을 반복하여 각 속성/값을 aa dynamic 에 추가하고 싶습니다 ExpandoObject
.
그래서 내가 필요한 것은
new { Prop1 = "first value", Prop2 = SomeObjectInstance, Prop3 = 1234 }
각 속성의 이름과 값을 알고 이를 에 추가할 수 있습니다 ExpandoObject
.
이 작업을 수행하려면 어떻게 해야 합니까?
참고 사항: 이것은 많은 단위 테스트에서 수행되므로(설정에서 많은 정크를 리팩터링하는 데 사용하고 있습니다) 성능은 어느 정도 관련이 있습니다. 나는 리플렉션에 대해 확실히 말할 만큼 충분히 알지 못하지만 내가 이해한 바에 따르면 성능이 상당히 무거우므로 가능하면 피하는 것이 좋습니다 ...
후속 질문: 내가 말했듯이 이 익명 개체를 메서드에 대한 인수로 사용합니다. 메서드의 서명에 어떤 데이터 유형을 사용해야 합니까? 를 사용하면 모든 속성을 사용할 수 object
있습니까?
foreach(var prop in myVar.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
Console.WriteLine("Name: {0}, Value: {1}",prop.Name, prop.GetValue(myVar,null));
}
익명 개체를 반영하여 속성 이름과 값을 가져온 다음 ExpandoObject를 실제로 사전으로 사용하여 채우십시오. 다음은 단위 테스트로 표현된 예입니다.
[TestMethod]
public void ShouldBeAbleToConvertAnAnonymousObjectToAnExpandoObject()
{
var additionalViewData = new {id = "myControlId", css = "hide well"};
dynamic result = new ExpandoObject();
var dict = (IDictionary<string, object>)result;
foreach (PropertyInfo propertyInfo in additionalViewData.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
dict[propertyInfo.Name] = propertyInfo.GetValue(additionalViewData, null);
}
Assert.AreEqual(result.id, "myControlId");
Assert.AreEqual(result.css, "hide well");
}
다른 접근 방식은 DynamicObject
대신 을 사용하는 것입니다 ExpandoObject
. 그렇게 하면 실제로 다른 객체에서 속성에 액세스하려고 할 때만 리플렉션을 수행하는 오버헤드가 발생합니다.
public class DynamicForwarder : DynamicObject
{
private object _target;
public DynamicForwarder(object target)
{
_target = target;
}
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
var prop = _target.GetType().GetProperty(binder.Name);
if (prop == null)
{
result = null;
return false;
}
result = prop.GetValue(_target, null);
return true;
}
}
이제 실제로 동적 get을 통해 속성에 액세스하려고 할 때만 리플렉션을 수행합니다. 단점은 동일한 속성에 반복적으로 액세스하면 매번 리플렉션을 수행해야 한다는 것입니다. 따라서 결과를 캐시할 수 있습니다.
public class DynamicForwarder : DynamicObject
{
private object _target;
private Dictionary<string, object> _cache = new Dictionary<string, object>();
public DynamicForwarder(object target)
{
_target = target;
}
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
// check the cache first
if (_cache.TryGetValue(binder.Name, out result))
return true;
var prop = _target.GetType().GetProperty(binder.Name);
if (prop == null)
{
result = null;
return false;
}
result = prop.GetValue(_target, null);
_cache.Add(binder.Name, result); // <-------- insert into cache
return true;
}
}
대상 개체 목록을 저장하여 속성을 통합하고 속성 설정을 지원( TrySetMember 라는 유사한 재정의 사용 )하여 캐시 사전에서 값을 동적으로 설정할 수 있습니다.
물론 리플렉션 오버헤드는 걱정할 가치가 없지만 큰 개체의 경우 반사의 영향을 제한할 수 있습니다. 더 흥미로운 점은 이것이 제공하는 추가적인 유연성입니다.
이것은 오래된 질문이지만 이제 다음 코드로 이 작업을 수행할 수 있습니다.
dynamic expObj = new ExpandoObject();
expObj.Name = "James Kirk";
expObj.Number = 34;
// print the dynamically added properties
// enumerating over it exposes the Properties and Values as a KeyValuePair
foreach (KeyValuePair<string, object> kvp in expObj){
Console.WriteLine("{0} = {1} : Type: {2}", kvp.Key, kvp.Value, kvp.Value.GetType());
}
출력은 다음과 같습니다.
이름 = James Kirk : 유형: System.String
번호 = 34 : 형식: System.Int32
리플렉션을 사용해야 합니다....( 이 URL에서 "빌려온" 코드 )
using System.Reflection; // reflection namespace
// get all public static properties of MyClass type
PropertyInfo[] propertyInfos;
propertyInfos = typeof(MyClass).GetProperties(BindingFlags.Public |
BindingFlags.Static);
// sort properties by name
Array.Sort(propertyInfos,
delegate(PropertyInfo propertyInfo1, PropertyInfo propertyInfo2)
{ return propertyInfo1.Name.CompareTo(propertyInfo2.Name); });
// write property names
foreach (PropertyInfo propertyInfo in propertyInfos)
{
Console.WriteLine(propertyInfo.Name);
}
Reflection.Emit을 사용하여 ExpandoObject를 채우는 일반 메서드를 만듭니다.
또는 아마도 표현식을 사용하십시오(이것은 .NET 4에서만 가능하다고 생각합니다).
이러한 접근 방식 중 어느 것도 호출할 때 리플렉션을 사용하지 않으며 대리자를 설정하는 동안에만(분명히 캐시해야 함) 리플렉션을 사용합니다.
다음은 사전을 채우기 위한 Reflection.Emit 코드입니다(ExpandoObject가 멀지 않은 것 같습니다).
static T CreateDelegate<T>(this DynamicMethod dm) where T : class
{
return dm.CreateDelegate(typeof(T)) as T;
}
static Dictionary<Type, Func<object, Dictionary<string, object>>> cache =
new Dictionary<Type, Func<object, Dictionary<string, object>>>();
static Dictionary<string, object> GetProperties(object o)
{
var t = o.GetType();
Func<object, Dictionary<string, object>> getter;
if (!cache.TryGetValue(t, out getter))
{
var rettype = typeof(Dictionary<string, object>);
var dm = new DynamicMethod(t.Name + ":GetProperties", rettype,
new Type[] { typeof(object) }, t);
var ilgen = dm.GetILGenerator();
var instance = ilgen.DeclareLocal(t);
var dict = ilgen.DeclareLocal(rettype);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Castclass, t);
ilgen.Emit(OpCodes.Stloc, instance);
ilgen.Emit(OpCodes.Newobj, rettype.GetConstructor(Type.EmptyTypes));
ilgen.Emit(OpCodes.Stloc, dict);
var add = rettype.GetMethod("Add");
foreach (var prop in t.GetProperties(
BindingFlags.Instance |
BindingFlags.Public))
{
ilgen.Emit(OpCodes.Ldloc, dict);
ilgen.Emit(OpCodes.Ldstr, prop.Name);
ilgen.Emit(OpCodes.Ldloc, instance);
ilgen.Emit(OpCodes.Ldfld, prop);
ilgen.Emit(OpCodes.Castclass, typeof(object));
ilgen.Emit(OpCodes.Callvirt, add);
}
ilgen.Emit(OpCodes.Ldloc, dict);
ilgen.Emit(OpCodes.Ret);
cache[t] = getter =
dm.CreateDelegate<Func<object, Dictionary<string, object>>>();
}
return getter(o);
}
ReferenceURL : https://stackoverflow.com/questions/2594527/how-do-i-iterate-over-the-properties-of-an-anonymous-object-in-c
'IT이야기' 카테고리의 다른 글
UITextField: 키보드가 나타날 때 보기 이동 (0) | 2021.10.09 |
---|---|
다국어 데이터를 보관하기 위한 최적의 데이터베이스 구조 (0) | 2021.10.09 |
문자와 혼합된 숫자만 인식하도록 tesseract를 만드는 방법 (0) | 2021.10.09 |
Android에서 카메라 손전등 사용 (0) | 2021.10.09 |
Android webview에서 키보드 아래에 숨겨진 텍스트 상자 (0) | 2021.10.09 |