当前位置: 动力学知识库 > 问答 > 编程问答 >

c# - Strange Reflection problem - can't get it

问题描述:

please help me understand what's going on in here and whether it should work like that ?

I have a generic list of objects from a CMS:

For example List<MyCMS.Articles.Article> myArticles = articles.All;

Later I output the contents of the list in a JSON format (for CMS UI - table list).

Now a single record would include:

article.Title

article.Alias

article.Guid

article.Description

+

article.SeoProperties.TitleOverride

article.SeoProperties.H1Tag

article.StateProperties.IsActive

article.StateProperties.Channels

etc...

as you can see an Article object has an additional class property - with common properties (used on other object types in the CMS)

I also use a filter class that does some filter operations with LINQ on the collection to return me only articles within a certain channel, for example...

So the problem is that when I serialize the collection as JSON - there are only a few "columns" that I really need to display in my table list, while I have no need in other fields - especially, possibly long fields such as "description" (lazy loaded from file system), etc... - I serialize with DataContractJsonSerializer...

I need a way to control what fields will be included in the JSON result... What I do is I use reflection to set property values to null if I don't need the property and

decorate class properties with [DataMember(IsRequired = false, EmitDefaultValue = false)] attributes... - it should work well - but - as soon as I go over (even cloned!!) collection of final objects to strip off the fields = set value to "null" - property value becomes null - application wide - in all collections of such objects... eh ?

Some demo code in here:

void Page_Load() {

MyCms.Content.Games games = new MyCms.Content.Games();

List<MyCms.Content.Games.Game> allGames = games.All;

MyCms.Content.Games games2 = new MyCms.Content.Games();

List<MyCms.Content.Games.Game> allGamesOther = games2.All;

Response.Write("Total games: " + allGames.Count + "<br />");

//This is our fields stripper - with result assigned to a new list

List<MyCms.Content.Games.Game> completelyUnrelatedOtherIsolated_but_notSureList = RemoveUnusedFields(allGamesOther);

List<MyCms.Content.Games.Game> gamesFiltered = allGames.Where(g=>g.GamingProperties.Software=="89070ef9-e115-4907-9996-6421e6013993").ToList();

Response.Write("Filtered games: " + gamesFiltered.Count + "<br /><br />");

}

private List<MyCms.Content.Games.Game> RemoveUnusedFields(List<MyCms.Content.Games.Game> games)

{

List<MyCms.Content.Games.Game> result = new List<MyCms.Content.Games.Game>();

if (games != null && games.Count > 0)

{

//Retrieve a list of current object properties

List<string> myContentProperties = MyCms.Utils.GetContentProperties(games[0]);

MyCms.PropertyReflector pF = new MyCms.PropertyReflector();

foreach (MyCms.Content.Games.Game contentItem in games)

{

MyCms.Content.Games.Game myNewGame = (MyCms.Content.Games.Game)contentItem.Clone();

myNewGame.Images = "wtf!"; //just to be sure we do set this stuff not only null

pF.SetValue(myNewGame, "GamingProperties.Software", ""); //set one property to null for testing

result.Add(myNewGame);

}

}

return result;

}

Objects are set to their "Default values" (basically, null, in most cases) with this:

 private object GetDefaultValue(Type type)

{

if (type.IsValueType)

{

try

{

return Activator.CreateInstance(type);

}

catch {

return null;

}

}

return null;

}

网友答案:

Quite probably your having trouble with differentiating between a shallow copy and a deep copy.

If a field is a value type, a bit-by-bit copy of the field is performed. If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object.

With a deep copy when you clone an object and that object has a field of reference type, a new clone of that object is created and assigned to the field (vs just referencing the first object). Thus you have to completely different objects that share nothing.

That means if you're using clone and some of the properties are in fact subproperties (that is, properties of an instance inside the original object) you're changing it application wide, because you're acting upon a reference, not a new instance of the subobject.

You have more information about it in

http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx

网友答案:

You could create a kind of modelview classes with the necessary fields and use something like Automapper to fill them. By this way, you will have a nice code, easy to maintain and highly customizable.

分享给朋友:
您可能感兴趣的文章:
随机阅读: