When does an object's property become available? - c#

Foreword: this is a long question and if you don't want to read and understand why I'm asking it then please spare the comment "why not simply test the code?"
I have an object model that looks somewhat like this:
public class MyObjectModel
{
public byte TypeOfNestedObject { get; set; }
public string NestedObjectInJson { get; set; }
public NestedObjectModel1 { get; set; }
public NestedObjectModel2 { get; set; }
public NestedObjectModel3 { get; set; }
public MyObjectModel()
{
NestedObjectModel1 = null;
NestedObjectModel2 = null;
NestedObjectModel3 = null;
}
public void DeserializeJsonString()
{
if (TypeOfNestedObject == 1) {
NestedObjectModel1 = "deserialize NestedObjectInJson
into NestedObjectModel1";
}
if (TypeOfNestedObject == 2) {
NestedObjectModel2 = "deserialize NestedObjectInJson
into NestedObjectModel2";
}
if (TypeOfNestedObject == 3) { NestedObjectModel3 ... }
}
}
Basically, the object is composed of three nested objects (NestedObjectModel1, NestedObjectModel2 and NestedObjectModel3). However, only one of them is actually used at any given time. In the database, I store fields that are used to recreate this object and one of the database fields is a json string that contains one of the three nested objects for a particular instance.
My query looks somewhat like this:
var TheObjectModel = from t in MyDC.Table
.....
select new MyObjectModel()
{
TypeOfNestedObject = t.TypeOfNestedObject,
NestedObjectInJson = t.NestedObjectInJson
};
I use the property TypeOfNestedObject to know which nested object the particular instance of MyObjectModel has. For the moment, after the the query has executed, I run a method that reads TypeOfNestedObject and deserializes the string NestedObjectInJson to the appropriate type and adds the deserialized object as the corresponding nested object.
Now I want to add a custom setter to NestedObjectInJson so that when this property is set when the query runs, the object automatically deserializes the string to the appropriate type. However, for this to work, the object would also have to have the property TypeOfNestedObject properly set. I want to write the setter like this:
public NestedObjectInJson
{
set {
if (this.TypeOfNestedObject == 1) {
NestedObjectModel1 = "deserialize NestedObjectInJson
into NestedObjectModel1 ";
}
}
}
If I write the setter like this, is the property TypeOfNestedObject needs to be available at the time the setter runs. If you notice, in the query, I load TypeOfNestedObject before I load NestedObjectInJson.
So the question is this: If I decide to remove the call to DeserializeJsonString and create this custom setter, will the property TypeOfNestedObject be available because in the query it's set before NestedObjectInJson or is the order in which the query is written make the availability of the property TypeOfNestedObject unpredictable?

This would work, the order is predictable.
However, I would advise against something like that. The clean approach would be to provide a constructor that takes the type and the JSON and performs the deserialization.
With that approach you would avoid the temporal coupling you currently have.

Related

Change an item property received from a linq query

I need to change the value of an item of a list returned by a query... It must be simple, but i can´t see it using linq.
The list is composed by elements of this structure:
public struct HeaderButton
{
public string content {get; set;}
public BitmapImage icon {get; set;}
public PageContainerFactory.ContainerType containerType {get; set;}
public bool IsSelected { get; set; }
}
private List<HeaderButton> _headerButtons;
public List<HeaderButton> HeaderButtons
{
get
{
if (_headerButtons == null)
_headerButtons = new List<HeaderButton>();
return _headerButtons;
}
set { _headerButtons = value; }
}
I´ve tried this:
HeaderButtons.First(x => x.containerType == CurrentContainer.CType).IsSelected = true;
And the compiler tells me:
Cannot modify the return value of 'System.Linq.Enumerable.First(System.Collections.Generic.IEnumerable, System.Func)' because it is not a variable
And now the query that i´m trying:
var h = HeaderButtons.First(x => x.containerType == CurrentContainer.CType);
h.IsSelected = true;
I had to take the element in a var because of the compiler error. And doing it as represented in the code above, obviously "h" does not points to the "HeaderButtons" real element since it is a new HeaderButton object and not a reference.
Following your comments, i decided to make a nested class in place of the structure since this kind of objects are not used outside of the content class, and now that is a class (object reference) and not a struct (value), everything works fine.
The code:
sealed class MainViewModel : ViewModelNavigator
{
internal class HeaderButton
{
public string Content { get; set; }
public BitmapImage Icon { get; set; }
public PageContainerFactory.ContainerType ContainerType { get; set; }
public bool IsSelected { get; set; }
}
...
private List<HeaderButton> _headerButtons;
public List<HeaderButton> HeaderButtons
{
get
{
if (_headerButtons == null)
_headerButtons = new List<HeaderButton>();
return _headerButtons;
}
set { _headerButtons = value; }
}
...
HeaderButtons.First(x => x.ContainerType == CurrentContainer.CType).IsSelected = true;
The compiler is saving you from shooting yourself in the foot.
Because HeaderButton is a struct it is passed by value instead of by reference. Which means that the Linq First operator is acting on (and will return) a value copy of the element in the list.
Because the return value from First is not assigned to anything it is temporary and will go out of scope at the end of the statement, and what's more since it is a value copy and not a reference to the item in the list any changes you make to it will not affect the item in the list anyway.
If this were to compile you might easily be misled to thinking that you had updated the item in the list, which you would not have. By refusing to compile the compiler is saving you from having to track down what could be a tricky bug to find.
If you have reason to keep HeaderButton as a struct then a statement like this will enable you to update it.
var hb = HeaderButtons.First(x => x.containerType == CurrentContainer.CType);
HeaderButtons[HeaderButtons.IndexOf(hb)].IsSelected = true;
If you go this route you need to ensure your struct's equality operations behave in a way that is useful to you, which hinges on the same factors as 'If you have reason to keep HeaderButton as a struct' because part of wanting to use a struct instead of a class means wanting value equality instead of reference equality semantics.

How can I efficiently design create / update methods, which need to create/update properties of different types?

I know, the question is long winded and probably difficult to understand, but hopefully someone has clicked on it and I can now explain in more detail what my issue is.
I have a Create method that is used to create an object called 'opportunity'. An opportunity has many different properties that need setting, but to make it simple I will use 'Title', 'Location', and 'StartDate'.
I also have an Update method that does something very similar and with regards to the properties listed it will set them in an identical way. However, as a side note I need 2 separate methods as they do differ.
Both methods take another object called an 'Entity' as a parameter, which is used to set the values for the 'opportunity'.
So, now to my issue. I was thinking the best approach is to have 1 method that does all of the property setting, which both methods use. I would pass a list of tuples to this method that contained 1.) the opportunity property name to be set, and 2.) the entity property value to set it to. However, to do this I would presumably need a tuple like string, object as the entity property value could be 1 of 5 types. Presumably this would cause boxing (and therefore is expensive). In addition to this I would be using the type to decide how to update the given opportunity property, so something like:
if (PropType == typeof(string))
{
//Do something
}
else if (PropType == typeof(Picklist))
{
//Do something else
}
else if (PropType == typeof(DateTime))
{
//Do something else
}
My question is, is this an efficient way of doing it? The 2 main reasons behind it for me are that it seems there is a lot of duplicate code between the create method and the update method as well as within each method with things like if(entity.prop.value != null) opp.prop.value = entity.prop.value. The second reason is that this way is easier to unit test. I can create a test for each opportunity property to be set and pass it into my new method as list of tuples and return if they've been created / updated correctly.
I considered a list of KeyValuePairs but I may need to add additional bits of info to the list so went with tuple. In addition, I think tuples are less expensive to pass to other methods (although more expensive to assign?).
I'm sure that despite my best efforts this still isn't clear, so any questions please ask.
EDIT
To give more clarity, there is an update method already in place (though I'm thinking of rewriting it) that has a lot of the same code in it to set the opportunity properties like this:
if(entity.Title.Value != null) opp.name = entity.Title.Value;
else throw new Exception("Title not specified");
if(entity.Town.Value != null) opp.town = entity.Town.Value;
else throw new Exception("Town not specified");
This is done for all string properties. My current view is I don't think I should need to duplicate this for all properties but rather have something that says:
//newOpp is passed in as the new opportunity
//Fields refers to a tuple passed in as object, string
//Item1 = entity field value
//Item2 = newOpp property name
PropertyInfo[] OppProps = newOpp.GetType().GetProperties();
PropertyInfo prop;
foreach (var record in Fields)
{
prop = OppProps.FirstOrDefault(x => x.Name == record.Item2);
if(record.Item1 != null && prop != null)
{
Type PropType = prop.GetType();
if (PropType == typeof(string))
{
prop.SetValue(newOpp, record.Item1, null);
}
//Extend to include other types used e.g. DateTime etc.
}
}
Because code says more then a few comment lines i made an example to illustrate what i mean.
public class Opportunity
{
public string Title { get; set; }
public string Location { get; set; }
public DateTime StartDate { get; set; }
}
public class OpportunityDto
{
public string Title { get; set; }
public string Location { get; set; }
[IgnoreMap]
public DateTime StartDate { get; set; }
}
public class Saver
{
public void CreateOpportunity(OpportunityDto dto)
{
var newOpportunity = new Opportunity();//You'll need some database logic here
MapProperties(dto, newOpportunity);
//Add save/create logic
}
public void UpdateOpportunity(OpportunityDto dto)
{
var existingUpportunity = new Opportunity();//you'll need some database query logic here
MapProperties(dto, existingUpportunity);
//Add save/update logic
}
public void MapProperties(OpportunityDto dto, Opportunity target)
{
Mapper.CreateMap<OpportunityDto, Opportunity>()
.ForAllMembers(opt => opt.Condition(srs => !srs.IsSourceValueNull));
Mapper.Map<OpportunityDto, Opportunity>(dto, target);
target.Startdate = dto.StartDate;//Insert more logic & mumbo jumbo here
//Or manually :
//target.Title = dto.Title;
//target.Location = dto.Location;
//target.StartDate = dto.StartDate;
}
}

Design Pattern for Object Modification with Timestamp

I have a colleciton of objects which need to maintain several time-stamps for that last time certain properties within the object was updated (one time-stamp per property).
I would just implement the time-stamp update in the setter except that the deserialization library being used first creates an object, then updates all of its properties (using the object's setter). This means that all my time-stamps would be invalidated every time my program deserializes them.
I'm thinking I need a singleton class or some update method which handles updating the properties and also controls the time-stamp update. Is there a better way to implement this behavior? Does a design pattern exist for this behavior?
If you separate your serialization concerns from your business layer, it should help find you some flexibility to hammer out a solution. Have 99% of your API work with your business object (which updates timestamps when properties update), then only convert to/from some data-transfer-object (DTO) for serialization purposes only.
For example, given some business object like this:
public class MyObject
{
public DateTime SomeValueUpdated { get; private set; }
private double _SomeValue;
public double SomeValue
{
get
{
return _SomeValue;
}
set
{
SomeValueUpdated = DateTime.Now;
_SomeValue = value;
}
}
public MyObject()
{
}
//for deserialization purposes only
public MyObject(double someValue, DateTime someValueUpdated)
{
this.SomeValue = someValue;
this.SomeValueUpdated = someValueUpdated;
}
}
You could have a matching DTO like this:
public class MyObjectDTO
{
public DateTime SomeValueUpdated { get; set; }
public double SomeValue { get; set; }
}
Your DTO can be specially adorned with various XML schema altering attributes, or you can manage the timestamps however you see fit and your business layer doesn't know and doesn't care.
When it comes time to serialize or deserialize the objects, run them through a converter utility:
public static class MyObjectDTOConverter
{
public static MyObjectDTO ToSerializable(MyObject myObj)
{
return new MyObjectDTO {
SomeValue = myObj.SomeValue,
SomeValueUpdated = myObj.SomeValueUpdated
};
}
public static MyObject FromSerializable(MyObjectDTO myObjSerialized)
{
return new MyObject(
myObjSerialized.SomeValue,
myObjSerialized.SomeValueUpdated
);
}
}
If you wish, you can make any of the properties or constructors of MyObject to be internal so only your conversion utility can access them. (For example, maybe you don't want to have the public MyObject(double someValue, DateTime someValueUpdated) constructor publicly accessible)

How to refer to a property of a class (not an object)?

I have a module that iterates through the public properties of an object (using Type.GetProperties()), and performs various operations on these properties. However, sometimes some of the properties should be handled differently, e.g., ignored. For example, suppose I have the following class:
class TestClass
{
public int Prop1 { get; set; }
public int Prop2 { get; set; }
}
Now, I would like to be able to specify that whenever my module gets an object of type TestClass, the property Prop2 should be ignored. Ideally I would like to be able to say something like this:
ReflectionIterator.AddToIgnoreList(TestClass::Prop2);
but that obviously doesn't work. I know I can get a PropertyInfo object if I first make an instance of the class, but it doesn't seem right to create an artificial instance just to do this. Is there any other way I can get a PropertyInfo-object for TestClass::Prop2?
(For the record, my current solution uses string literals, which are then compared with each property iterated through, like this:
ReflectionIterator.AddToIgnoreList("NamespaceName.TestClass.Prop2");
and then when iterating over the properties:
foreach (var propinfo in obj.GetProperties())
{
if (ignoredProperties.Contains(obj.GetType().FullName + "." + propinfo.Name))
// Ignore
// ...
}
but this solution seems a bit messy and error-prone...)
List<PropertyInfo> ignoredList = ...
ignoredList.Add(typeof(TestClass).GetProperty("Prop2"));
should do the job... just check whether ignoredList.Contains(propinfo)
Could you add attributes to the properties to define how they should be used? eg
class TestClass
{
public int Prop1 { get; set; }
[Ignore]
public int Prop2 { get; set; }
}

Dynamic Linq Library Help

I have the following class:
public class Item
{
public Dictionary<string, string> Data
{
get;
set;
}
}
and a list of it:
List<Item> items;
I need to filter and order this list dynamically using SQL-Like strings. The catch is, that I need to order it by the Data dictionary.
For example: Order By Data["lastname"] or Where Data["Name"].StartsWith("a"). I thought to use the dynamic linq library, but is there any way that my clients can write without the Data[]? For example:
Name.StartsWith("abc")
instead of
Data["Name"].StartsWith("abc")
?
You could add a property like this:
public class Item
{
public Dictionary<string, string> Data
{ get; set; }
public string Name { get { return Data["lastname"]; } }
}
//Call by: i.Name.StartsWith("abc");
Or an extension method:
public static class ItemExtensions
{
public static string Name(this Item item)
{
return item.Data["lastname"];
}
}
//Call by: i.Name().StartsWith("abc");
Or if it's a very commonly used method, you could add something like a .NameStartsWith():
public static string NameStartsWith(this Item item, stirng start)
{
return item.Data["lastname"].StartsWith(start);
}
//Call by: i.NameStartsWith("abc");
This doesn't have anything to do with the Linq Dynamic Query unit. That unit is for when you have actual fields/properties and the names of them will be given to you at runtime. In other words, you have a class like this:
public class Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
And you want to be able to write a query like this:
var sortedPeople = people.OrderBy("FirstName");
You are trying to do the exact opposite of this - you have a class that does not have any actual properties, just an attribute dictionary, and you want compile-time safety. You can't have it; there's no way to guarantee that an item will be in the dictionary, especially when the dictionary is public and anyone can add/remove directly from it!
If there's some reason that you must use that specific class design, then you could conceivably write some wrappers as Nick has presented, but I wouldn't even bother - they're not actually providing any encapsulation because the Data dictionary is still wide open to the whole world. Instead, I would just provide a single safe getter method or indexer property and create a few constants (or an enum) with the names of properties you expect to be in there.
public class Item
{
public Dictionary<string, string> Data { get; set; }
public string GetValue(string key)
{
if (Data == null)
return null;
string result;
Data.TryGetValue(key, out result);
return result;
}
}
public class ItemKeys
{
public const string Name = "Name";
public const string Foo = "Foo";
}
And so on. Really the ItemKeys isn't that important, the safe GetValue method is what's important, because otherwise you run the risk of a NullReferenceException if Data hasn't been assigned, or a KeyNotFoundException if even one Item instance doesn't have that property. Using the GetValue method here will succeed no matter what:
var myItems = items.OrderBy(i => i.GetValue(ItemKeys.Name));
If you find you're writing a lot of repetitive code for the same attributes, then start worrying about adding shortcut properties or extension methods to the class.
I assume that you don't know the names of the properties at compile-time (in which case, you could simply define properties and wouldn't have this problem). I have two suggestions that you could try, but I didn't implement any of them myself, so I can't guarantee that it will work.
If you can use .NET 4.0, you could inherit from DynamicObject and implement TryGetMember method (which is called when you use o.Foo on an object that is declared as dynamic). Assuming that Dynamic LINQ works with DLR, it should automatically invoke this method for objects that inherit from DynamicObject. Inside the TryGetMember method, you would get a name of the accessed property, so you could perform a dictionary lookup. (However, this solution would work only if Dynamic LINQ integrates well with DLR).
In any case, you could do some basic parsing of the string entered by the user and replace for example Name with Data["Name"]. This would definitely work, but it may be a bit difficult (because you should probably at least check that you're doing the replace in correct context - e.g. not inside a string constant).
Regarding extension methods - I'm not sure if Dynamic LINQ handles extension methods (but, I don't think so, because that would require searching all referenced assemblies)

Categories

Resources