C #에서 리플렉션을 사용하여 중첩 된 개체의 속성 가져 오기
다음 개체가 주어지면 :
public class Customer {
public String Name { get; set; }
public String Address { get; set; }
}
public class Invoice {
public String ID { get; set; }
public DateTime Date { get; set; }
public Customer BillTo { get; set; }
}
나는 통과하는 반사를 사용하고 싶습니다 Invoice
얻을 Name
의 속성을 Customer
. 이 코드가 작동한다고 가정하면 다음과 같습니다.
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);
물론 이것은 "BillTo.Address"가 Invoice
클래스 의 유효한 속성이 아니기 때문에 실패합니다 .
그래서 저는 그 기간에 문자열을 조각으로 나누는 방법을 작성하고 내가 관심이있는 최종 값을 찾기 위해 객체를 걷는 방법을 시도했습니다. 그것은 잘 작동하지만 완전히 편안하지는 않습니다.
public Object GetPropValue(String name, Object obj) {
foreach (String part in name.Split('.')) {
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
이 방법을 개선하는 방법 또는이 문제를 해결하는 더 나은 방법에 대한 아이디어가 있습니까?
게시 후 편집 , 몇 가지 관련 게시물을 보았습니다 ... 그러나이 질문을 구체적으로 다루는 답변은없는 것 같습니다. 또한 내 구현에 대한 피드백을 받고 싶습니다.
나는 실제로 당신의 논리가 괜찮다고 생각합니다. 개인적으로 나는 아마도 그것을 변경하여 첫 번째 매개 변수로 개체를 전달합니다 (PropertyInfo.GetValue와 더 인라인이므로 덜 놀랍습니다).
또한 속성 스택을 아래로 검색한다는 것을 분명히하기 위해 GetNestedPropertyValue와 같은 이름으로 호출 할 수도 있습니다.
이 방법을 사용하여 다음과 같은 속성에서 값을 가져옵니다.
"특성"
"주소. 거리"
"주소. 국가. 이름"
public static object GetPropertyValue(object src, string propName)
{
if (src == null) throw new ArgumentException("Value cannot be null.", "src");
if (propName == null) throw new ArgumentException("Value cannot be null.", "propName");
if(propName.Contains("."))//complex type nested
{
var temp = propName.Split(new char[] { '.' }, 2);
return GetPropertyValue(GetPropertyValue(src, temp[0]), temp[1]);
}
else
{
var prop = src.GetType().GetProperty(propName);
return prop != null ? prop.GetValue(src, null) : null;
}
}
여기 바이올린 : https://dotnetfiddle.net/PvKRH0
리플렉션을 사용해야하는 ACTUAL 개체에 액세스해야합니다. 내가 의미하는 바는 다음과 같습니다.
대신 :
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo.Address");
Object val = info.GetValue(inv, null);
다음을 수행하십시오 (코멘트에 따라 편집 됨).
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
PropertyInfo info = inv.GetType().GetProperty("BillTo");
Customer cust = (Customer)info.GetValue(inv, null);
PropertyInfo info2 = cust.GetType().GetProperty("Address");
Object val = info2.GetValue(cust, null);
자세한 내용은이 게시물을 참조하십시오. 반사를 사용하여 개체 속성의 속성 설정
나는 파티에 조금 늦게 해요 알고, 다른 사람들이 말했듯이, 구현 괜찮습니다
... 간단한 사용 사례에 대해 .
그러나 저는 그 사용 사례를 정확히 해결하는 라이브러리 인 Pather.CSharp를 개발했습니다 . Nuget Package
로도 제공됩니다 .
주요 클래스는 Resolver
그와 Resolve
방법.
당신은 그에게 전달할 객체와 속성 경로를 , 그리고 그것은 반환 원하는 값을 .
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
var resolver = new Resolver();
object result = resolver.Resolve(inv, "BillTo.Address");
그러나 배열 및 사전 액세스를 포함하여 더 복잡한 속성 경로를 해결할 수도 있습니다.
예를 들어 주소Customer
가 여러 개인 경우
public class Customer {
public String Name { get; set; }
public IEnumerable<String> Addresses { get; set; }
}
을 사용하여 두 번째 항목에 액세스 할 수 있습니다 Addresses[1]
.
Invoice inv = GetDesiredInvoice(); // magic method to get an invoice
var resolver = new Resolver();
object result = resolver.Resolve(inv, "BillTo.Addresses[1]");
파티에 너무 늦게 들리지 않기를 바라면서 내 솔루션을 추가하고 싶습니다.이 상황에서 재귀를 사용하십시오.
public static Object GetPropValue(String name, object obj, Type type)
{
var parts = name.Split('.').ToList();
var currentPart = parts[0];
PropertyInfo info = type.GetProperty(currentPart);
if (info == null) { return null; }
if (name.IndexOf(".") > -1)
{
parts.Remove(currentPart);
return GetPropValue(String.Join(".", parts), info.GetValue(obj, null), info.PropertyType);
} else
{
return info.GetValue(obj, null).ToString();
}
}
당신은 당신의 "불편 함"의 원인을 설명하지 않지만, 당신의 코드는 기본적으로 나에게 소리가 나는 것처럼 보인다.
내가 질문 할 유일한 것은 오류 처리입니다. 코드가 null 참조를 통과하려고 시도하거나 속성 이름이 존재하지 않는 경우 null을 반환합니다. 이렇게하면 오류가 숨겨집니다. BillTo 고객이 없기 때문에 null을 반환했는지 또는 "BilTo.Address"철자가 틀 렸기 때문에 또는 BillTo 고객이 있고 해당 주소가 null이기 때문에 null을 반환했는지 알기 어렵습니다! 이 경우 메서드가 충돌하고 태워 지도록했습니다. 예외를 탈출 시키거나 더 친숙한 것으로 래핑하면됩니다.
> Get Nest properties e.g., Developer.Project.Name
private static System.Reflection.PropertyInfo GetProperty(object t, string PropertName)
{
if (t.GetType().GetProperties().Count(p => p.Name == PropertName.Split('.')[0]) == 0)
throw new ArgumentNullException(string.Format("Property {0}, is not exists in object {1}", PropertName, t.ToString()));
if (PropertName.Split('.').Length == 1)
return t.GetType().GetProperty(PropertName);
else
return GetProperty(t.GetType().GetProperty(PropertName.Split('.')[0]).GetValue(t, null), PropertName.Split('.')[1]);
}
if (info == null) { /* throw exception instead*/ }
존재하지 않는 속성을 요청하면 실제로 예외가 발생합니다. 코딩 한 방식에 따라 GetPropValue를 호출하고 null을 반환하면 속성이 존재하지 않았는지 또는 속성이 존재하지만 값이 null인지는 알 수 없습니다.
public static string GetObjectPropertyValue(object obj, string propertyName)
{
bool propertyHasDot = propertyName.IndexOf(".") > -1;
string firstPartBeforeDot;
string nextParts = "";
if (!propertyHasDot)
firstPartBeforeDot = propertyName.ToLower();
else
{
firstPartBeforeDot = propertyName.Substring(0, propertyName.IndexOf(".")).ToLower();
nextParts = propertyName.Substring(propertyName.IndexOf(".") + 1);
}
foreach (var property in obj.GetType().GetProperties())
if (property.Name.ToLower() == firstPartBeforeDot)
if (!propertyHasDot)
if (property.GetValue(obj, null) != null)
return property.GetValue(obj, null).ToString();
else
return DefaultValue(property.GetValue(obj, null), propertyName).ToString();
else
return GetObjectPropertyValue(property.GetValue(obj, null), nextParts);
throw new Exception("Property '" + propertyName.ToString() + "' not found in object '" + obj.ToString() + "'");
}
Here is another implementation that will skip a nested property if it is an enumerator and continue deeper. Properties of type string are not affected by the Enumeration Check.
public static class ReflectionMethods
{
public static bool IsNonStringEnumerable(this PropertyInfo pi)
{
return pi != null && pi.PropertyType.IsNonStringEnumerable();
}
public static bool IsNonStringEnumerable(this object instance)
{
return instance != null && instance.GetType().IsNonStringEnumerable();
}
public static bool IsNonStringEnumerable(this Type type)
{
if (type == null || type == typeof(string))
return false;
return typeof(IEnumerable).IsAssignableFrom(type);
}
public static Object GetPropValue(String name, Object obj)
{
foreach (String part in name.Split('.'))
{
if (obj == null) { return null; }
if (obj.IsNonStringEnumerable())
{
var toEnumerable = (IEnumerable)obj;
var iterator = toEnumerable.GetEnumerator();
if (!iterator.MoveNext())
{
return null;
}
obj = iterator.Current;
}
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
}
based on this question and on
I use this in a MVC project to dynamically Order my data by simply passing the Property to sort by Example:
result = result.OrderBy((s) =>
{
return ReflectionMethods.GetPropValue("BookingItems.EventId", s);
}).ToList();
where BookingItems is a list of objects.
My internet connection was down when I need to solve the same problem, so I had to 're-invent the wheel':
static object GetPropertyValue(Object fromObject, string propertyName)
{
Type objectType = fromObject.GetType();
PropertyInfo propInfo = objectType.GetProperty(propertyName);
if (propInfo == null && propertyName.Contains('.'))
{
string firstProp = propertyName.Substring(0, propertyName.IndexOf('.'));
propInfo = objectType.GetProperty(firstProp);
if (propInfo == null)//property name is invalid
{
throw new ArgumentException(String.Format("Property {0} is not a valid property of {1}.", firstProp, fromObject.GetType().ToString()));
}
return GetPropertyValue(propInfo.GetValue(fromObject, null), propertyName.Substring(propertyName.IndexOf('.') + 1));
}
else
{
return propInfo.GetValue(fromObject, null);
}
}
Pretty sure this solves the problem for any string you use for property name, regardless of extent of nesting, as long as everything's a property.
Try inv.GetType().GetProperty("BillTo+Address");
'developer tip' 카테고리의 다른 글
package-lock.json에 정의 된 종속성의 잠재적 보안 취약성을 수정하는 적절한 방법 (0) | 2020.11.12 |
---|---|
Entity Framework는 재귀 계층과 어떻게 작동합니까? (0) | 2020.11.12 |
Amazone의 EC2 인스턴스에서 코드를 실행하는 방법은 무엇입니까? (0) | 2020.11.12 |
단일 열을 반환하는 SQL Alchemy ORM, 일반적인 사후 처리를 방지하는 방법 (0) | 2020.11.12 |
Visual Studio 2010의 CSS 3.0 (0) | 2020.11.12 |