从未知对象获取属性和值

在PHP的世界里,我决定尝试一下C#。我搜索了一下,但似乎找不到如何做与此相当的事情的答案。

$object = new Object();


$vars = get_class_vars(get_class($object));


foreach($vars as $var)
{
doSomething($object->$var);
}

我基本上有一个对象的列表。该对象可以是三种不同类型中的一种,并将具有一组公共属性。我希望能够获得对象的属性列表,对它们进行循环,然后将它们写入文件。 我认为这与C#反射有关,但这对我来说是全新的。

任何帮助都将不胜感激。

416112 次浏览

Yes, Reflection would be the way to go. First, you would get the Type that represents the type (at runtime) of the instance in the list. You can do this by calling the __ABC1 method on Object. Because it is on the Object class, it's callable by every object in .NET, as all types derive from Object (well, technically, not everything, but that's not important here).

Once you have the Type instance, you can call the GetProperties method to get the PropertyInfo instances which represent the run-time informationa about the properties on the Type.

Note, you can use the overloads of GetProperties to help classify which properties you retrieve.

From there, you would just write the information out to a file.

Your code above, translated, would be:

// The instance, it can be of any type.
object o = <some object>;


// Get the type.
Type type = o.GetType();


// Get all public instance properties.
// Use the override if you want to classify
// which properties to return.
foreach (PropertyInfo info in type.GetProperties())
{
// Do something with the property info.
DoSomething(info);
}

Note that if you want method information or field information, you would have to call the one of the overloads of the GetMethods or GetFields methods respectively.

Also note, it's one thing to list out the members to a file, but you shouldn't use this information to drive logic based on property sets.

Assuming you have control over the implementations of the types, you should derive from a common base class or implement a common interface and make the calls on those (you can use the as or is operator to help determine which base class/interface you are working with at runtime).

However, if you don't control these type definitions and have to drive logic based on pattern matching, then that's fine.

Here's something I use to transform an IEnumerable<T> into a DataTable that contains columns representing T's properties, with one row for each item in the IEnumerable:

public static DataTable ToDataTable<T>(IEnumerable<T> items)
{
var table = CreateDataTableForPropertiesOfType<T>();
PropertyInfo[] piT = typeof(T).GetProperties();
foreach (var item in items)
{
var dr = table.NewRow();
for (int property = 0; property < table.Columns.Count; property++)
{
if (piT[property].CanRead)
{
var value = piT[property].GetValue(item, null);
if (piT[property].PropertyType.IsGenericType)
{
if (value == null)
{
dr[property] = DBNull.Value;
}
else
{
dr[property] = piT[property].GetValue(item, null);
}
}
else
{
dr[property] = piT[property].GetValue(item, null);
}
}
}
table.Rows.Add(dr);
}
return table;
}


public static DataTable CreateDataTableForPropertiesOfType<T>()
{
DataTable dt = new DataTable();
PropertyInfo[] piT = typeof(T).GetProperties();
foreach (PropertyInfo pi in piT)
{
Type propertyType = null;
if (pi.PropertyType.IsGenericType)
{
propertyType = pi.PropertyType.GetGenericArguments()[0];
}
else
{
propertyType = pi.PropertyType;
}
DataColumn dc = new DataColumn(pi.Name, propertyType);


if (pi.CanRead)
{
dt.Columns.Add(dc);
}
}
return dt;
}

This is "somewhat" overcomplicated, but it's actually quite good for seeing what the outcome is, as you can give it a List<T> of, for example:

public class Car
{
string Make { get; set; }
int YearOfManufacture {get; set; }
}

And you'll be returned a DataTable with the structure:

Make (string)
YearOfManufacture (int)

With one row per item in your List<Car>

well, in C# it's similar. Here's one of the simplest examples (only for public properties):

var someObject = new { .../*properties*/... };
var propertyInfos = someObject.GetType().GetProperties();
foreach (PropertyInfo pInfo in propertyInfos)
{
string propertyName = pInfo.Name; //gets the name of the property
doSomething(pInfo.GetValue(someObject,null));
}

This should do it:

Type myType = myObject.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());


foreach (PropertyInfo prop in props)
{
object propValue = prop.GetValue(myObject, null);


// Do something with propValue
}

This example trims all the string properties of an object.

public static void TrimModelProperties(Type type, object obj)
{
var propertyInfoArray = type.GetProperties(
BindingFlags.Public |
BindingFlags.Instance);
foreach (var propertyInfo in propertyInfoArray)
{
var propValue = propertyInfo.GetValue(obj, null);
if (propValue == null)
continue;
if (propValue.GetType().Name == "String")
propertyInfo.SetValue(
obj,
((string)propValue).Trim(),
null);
}
}

To get specific property value from property name

public class Bike{
public string Name {get;set;}
}


Bike b = new Bike {Name = "MyBike"};

to access property value of Name from string name of property

public object GetPropertyValue(string propertyName)
{
//returns value of property Name
return this.GetType().GetProperty(propertyName).GetValue(this, null);
}

You can use GetType - GetProperties - Linq Foreach:

obj.GetType().GetProperties().ToList().ForEach(p =>{
//p is each PropertyInfo
DoSomething(p);
});
void Test(){
var obj = new{a="aaa", b="bbb"};


var val_a = obj.GetValObjDy("a"); //="aaa"
var val_b = obj.GetValObjDy("b"); //="bbb"
}
//create in a static class
static public object GetValObjDy(this object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName).GetValue(obj, null);
}

I haven't found this to work on, say Application objects. I have however had success with

var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();


string rval = serializer.Serialize(myAppObj);

You can try this:

string[] arr = ((IEnumerable)obj).Cast<object>()
.Select(x => x.ToString())
.ToArray();

Once every array implements IEnumerable interface

One line solution using Linq...

var obj = new {Property1 = 1, Property2 = 2};
var property1 = obj.GetType().GetProperties().First(o => o.Name == "Property1").GetValue(obj , null);
public Dictionary<string, string> ToDictionary(object obj)
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();


Type objectType = obj.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(objectType.GetProperties());


foreach (PropertyInfo prop in props)
{
object propValue = prop.GetValue(obj, null);
dictionary.Add(prop.Name, propValue.ToString());
}


return dictionary;
}
    /// get set value field in object to object new (two object  field like )


public static void SetValueObjectToObject (object sourceObj , object resultObj)
{
IList<PropertyInfo> props = new List<PropertyInfo>(sourceObj.GetType().GetProperties());
foreach (PropertyInfo prop in props)
{
try
{
//get value in sourceObj
object propValue = prop.GetValue(sourceObj, null);
//set value in resultObj
PropertyInfo propResult = resultObj.GetType().GetProperty(prop.Name, BindingFlags.Public | BindingFlags.Instance);
if (propResult != null && propResult.CanWrite)
{
propResult.SetValue(resultObj, propValue, null);
}
}
catch (Exception ex)
{
// do something with Ex
}
}
}