C #에서 익명 유형의 속성에 액세스하는 방법은 무엇입니까?
나는 이것을 가지고있다:
List<object> nodes = new List<object>();
nodes.Add(
new {
Checked = false,
depth = 1,
id = "div_" + d.Id
});
... 그리고 익명 객체의 "Checked"속성을 가져올 수 있는지 궁금합니다. 이것이 가능한지 확실하지 않습니다. 이것을 시도했다 :
if (nodes.Any(n => n["Checked"] == false))
...하지만 작동하지 않습니다.
감사
강력한 유형의 익명 유형 목록을 원하면 목록을 익명 유형으로 만들어야합니다. 가장 쉬운 방법은 배열과 같은 시퀀스를 목록에 투영하는 것입니다.
var nodes = (new[] { new { Checked = false, /* etc */ } }).ToList();
그러면 다음과 같이 액세스 할 수 있습니다.
nodes.Any(n => n.Checked);
컴파일러의 작동 방식으로 인해 익명 유형이 동일한 구조를 갖기 때문에 동일한 유형이기 때문에 목록을 작성한 후에는 다음도 작동해야합니다. 그래도 이것을 확인할 수있는 컴파일러가 없습니다.
nodes.Add(new { Checked = false, /* etc */ });
객체를 type으로 저장하는 object
경우 리플렉션을 사용해야합니다. 익명 또는 기타의 모든 개체 유형에 적용됩니다. 객체 o에서 다음과 같은 유형을 얻을 수 있습니다.
Type t = o.GetType();
그런 다음 속성을 찾습니다.
PropertyInfo p = t.GetProperty("Foo");
그런 다음 그 값을 얻을 수 있습니다.
object v = p.GetValue(o, null);
이 답변은 C # 4에 대한 업데이트가 오래되었습니다.
dynamic d = o;
object v = d.Foo;
이제 C # 6의 또 다른 대안 :
object v = o?.GetType().GetProperty("Foo")?.GetValue(o, null);
를 사용 ?.
하면 결과 v
가 null
세 가지 다른 상황에있게됩니다!
o
이다null
, 그래서 객체는 전혀 없다o
비-null
하지만 속성이 없습니다Foo
o
속성이Foo
있지만 실제 값은입니다null
.
따라서 이것은 이전 예제와 동일하지 않지만 세 가지 경우를 모두 동일하게 취급하려는 경우 이치에 맞습니다.
Reflection을 사용하여 익명 형식의 속성을 반복 할 수 있습니다. "Checked"속성이 있는지 확인하고 값이 있으면 확인하십시오.
이 블로그 게시물 참조 : http://blogs.msdn.com/wriju/archive/2007/10/26/c-3-0-anonymous-type-and-net-reflection-hand-in-hand.aspx
그래서 같은 :
foreach(object o in nodes)
{
Type t = o.GetType();
PropertyInfo[] pi = t.GetProperties();
foreach (PropertyInfo p in pi)
{
if (p.Name=="Checked" && !(bool)p.GetValue(o))
Console.WriteLine("awesome!");
}
}
최근에 .NET 3.5에서 동일한 문제가 발생했습니다 (동적 사용 가능하지 않음). 내가 해결 한 방법은 다음과 같습니다.
// pass anonymous object as argument
var args = new { Title = "Find", Type = typeof(FindCondition) };
using (frmFind f = new frmFind(args))
{
...
...
}
스택 오버 플로우의 어딘가에서 적응 :
// Use a custom cast extension
public static T CastTo<T>(this Object x, T targetType)
{
return (T)x;
}
이제 캐스트를 통해 객체를 다시 가져옵니다.
public partial class frmFind: Form
{
public frmFind(object arguments)
{
InitializeComponent();
var args = arguments.CastTo(new { Title = "", Type = typeof(Nullable) });
this.Text = args.Title;
...
}
...
}
수락 된 답변은 목록을 어떻게 선언해야하는지 정확하게 설명하며 대부분의 시나리오에 권장됩니다.
그러나 나는 다른 시나리오를 보았습니다.이 시나리오는 또한 질문 된 질문을 다룹니다. ViewData["htmlAttributes"]
MVC 에서와 같이 기존 객체 목록을 사용해야하는 경우 어떻게 합니까? 속성에 어떻게 액세스 할 수 new { @style="width: 100px", ... }
있습니까 ( 보통을 통해 생성됨 )?
For this slightly different scenario I want to share with you what I found out. In the solutions below, I am assuming the following declaration for nodes
:
List<object> nodes = new List<object>();
nodes.Add(
new
{
Checked = false,
depth = 1,
id = "div_1"
});
1. Solution with dynamic
In C# 4.0 and higher versions, you can simply cast to dynamic and write:
if (nodes.Any(n => ((dynamic)n).Checked == false))
Console.WriteLine("found not checked element!");
Note: This is using late binding, which means it will recognize only at runtime if the object doesn't have a Checked
property and throws a RuntimeBinderException
in this case - so if you try to use a non-existing Checked2
property you would get the following message at runtime: "'<>f__AnonymousType0<bool,int,string>' does not contain a definition for 'Checked2'"
.
2. Solution with reflection
The solution with reflection works both with old and new C# compiler versions. For old C# versions please regard the hint at the end of this answer.
Background
As a starting point, I found a good answer here. The idea is to convert the anonymous data type into a dictionary by using reflection. The dictionary makes it easy to access the properties, since their names are stored as keys (you can access them like myDict["myProperty"]
).
Inspired by the code in the link above, I created an extension class providing GetProp
, UnanonymizeProperties
and UnanonymizeListItems
as extension methods, which simplify access to anonymous properties. With this class you can simply do the query as follows:
if (nodes.UnanonymizeListItems().Any(n => (bool)n["Checked"] == false))
{
Console.WriteLine("found not checked element!");
}
or you can use the expression nodes.UnanonymizeListItems(x => (bool)x["Checked"] == false).Any()
as if
condition, which filters implicitly and then checks if there are any elements returned.
To get the first object containing "Checked" property and return its property "depth", you can use:
var depth = nodes.UnanonymizeListItems()
?.FirstOrDefault(n => n.Contains("Checked")).GetProp("depth");
or shorter: nodes.UnanonymizeListItems()?.FirstOrDefault(n => n.Contains("Checked"))?["depth"];
Note: If you have a list of objects which don't necessarily contain all properties (for example, some do not contain the "Checked" property), and you still want to build up a query based on "Checked" values, you can do this:
if (nodes.UnanonymizeListItems(x => { var y = ((bool?)x.GetProp("Checked", true));
return y.HasValue && y.Value == false;}).Any())
{
Console.WriteLine("found not checked element!");
}
This prevents, that a KeyNotFoundException
occurs if the "Checked" property does not exist.
The class below contains the following extension methods:
UnanonymizeProperties
: Is used to de-anonymize the properties contained in an object. This method uses reflection. It converts the object into a dictionary containing the properties and its values.UnanonymizeListItems
: Is used to convert a list of objects into a list of dictionaries containing the properties. It may optionally contain a lambda expression to filter beforehand.GetProp
: Is used to return a single value matching the given property name. Allows to treat not-existing properties as null values (true) rather than as KeyNotFoundException (false)
For the examples above, all that is required is that you add the extension class below:
public static class AnonymousTypeExtensions
{
// makes properties of object accessible
public static IDictionary UnanonymizeProperties(this object obj)
{
Type type = obj?.GetType();
var properties = type?.GetProperties()
?.Select(n => n.Name)
?.ToDictionary(k => k, k => type.GetProperty(k).GetValue(obj, null));
return properties;
}
// converts object list into list of properties that meet the filterCriteria
public static List<IDictionary> UnanonymizeListItems(this List<object> objectList,
Func<IDictionary<string, object>, bool> filterCriteria=default)
{
var accessibleList = new List<IDictionary>();
foreach (object obj in objectList)
{
var props = obj.UnanonymizeProperties();
if (filterCriteria == default
|| filterCriteria((IDictionary<string, object>)props) == true)
{ accessibleList.Add(props); }
}
return accessibleList;
}
// returns specific property, i.e. obj.GetProp(propertyName)
// requires prior usage of AccessListItems and selection of one element, because
// object needs to be a IDictionary<string, object>
public static object GetProp(this object obj, string propertyName,
bool treatNotFoundAsNull = false)
{
try
{
return ((System.Collections.Generic.IDictionary<string, object>)obj)
?[propertyName];
}
catch (KeyNotFoundException)
{
if (treatNotFoundAsNull) return default(object); else throw;
}
}
}
Hint: The code above is using the null-conditional operators, available since C# version 6.0 - if you're working with older C# compilers (e.g. C# 3.0), simply replace ?.
by .
and ?[
by [
everywhere, e.g.
var depth = nodes.UnanonymizeListItems()
.FirstOrDefault(n => n.Contains("Checked"))["depth"];
If you're not forced to use an older C# compiler, keep it as is, because using null-conditionals makes null handling much easier.
Note: Like the other solution with dynamic, this solution is also using late binding, but in this case you're not getting an exception - it will simply not find the element if you're referring to a non-existing property, as long as you keep the null-conditional operators.
What might be useful for some applications is that the property is referred to via a string in solution 2, hence it can be parameterized.
참고URL : https://stackoverflow.com/questions/1203522/how-to-access-property-of-anonymous-type-in-c
'IT story' 카테고리의 다른 글
인앱 결제 테스트 : android.test.purchased 이미 소유 (0) | 2020.08.04 |
---|---|
Nullable과 함께 DateTime.TryParse를 사용하는 방법 (0) | 2020.08.04 |
.NET 4.0에서 SmtpClient, SendAsync 및 Dispose 사용에 대한 모범 사례는 무엇입니까? (0) | 2020.08.04 |
Java에서 SHA-256을 통한 해시 문자열 (0) | 2020.08.04 |
if 문을 사용하여 div가 비어 있는지 확인 (0) | 2020.08.04 |