How to limit a string to a set of dynamically-defined values? - c#

I have a class that has a string property for which I'd like to limit the possible values to a set defined dynamically (e.g. stored in the database, though we're using code-first EF6). Using an Enum is obviously out. I did some reading about Code Contracts and like the look of that, but don't know the first thing about establishing a Contract.Requires that pulls back a set of values. Lambda, maybe? I'm on the bleeding edge of my understanding here.
Here's some sample code:
public class Rule
{
/// <summary>The Conditions associated with this Rule
/// </summary>
public ICollection<Condition> Conditions { get; set; }
// ... some other stuff ...
/// <summary>The Status of the Rule.
/// </summary>
public string RuleStatus
{
get{}
set
{
// Here's where I want to dynamically determine values
Contract.Requires(value == "Inactive"||"Obsolete");
// Perhaps something like this,
// where GetValidRuleStatuses returns an array of string??
Contract.Requires(GetValidRuleStatuses().Contains(value));
}
}

One way to do this, is to write custom code to actually perform the check as and when you need to.
In terms of data structures, I'd recommend a HashSet<string> for fast lookups, which you will need to populate:
//Cache this somewhere, until the values change
var allowedValues = new HashSet<string>(stringValues);
if(!allowedValues.Contains(attemptedValue))
{
//Throw exception?
}

Related

C# - Field values set with reflection aren't updating [duplicate]

This question already has answers here:
Why doesn't reflection set a property in a Struct?
(3 answers)
Closed last month.
I'm making a statistics system for a Unity game and attempting to write some functions that update a given statistic (identified by their field name) with a given value using reflection. I know reflection can be controversial but I thought it would be better practice than exposing the fields containing the statistics structs. The only issue is that the field values don't seem to be actually updating -- printing the before and after field values shows that they remain the same even after these functions are called.
Here's what I've tried for now. _lifetimeStats is a private static struct which contains various fields holding different statistics. The int is being used on fields which are already defined as ints.
private static LifetimeStatistics _lifetimeStats;
/// <summary>
/// Replaces the current value of the statistic with the provided value.
/// See also: <see cref="UpdateLifetimeStat"/>
/// </summary>
public static void SetLifetimeStat(string statName, object value)
{
var stat = _lifetimeStats.GetType().GetField(statName);
stat.SetValue(_lifetimeStats, value);
}
/// <summary>
/// Adds the provided value to the current value of the statistic.
/// See also: <see cref="SetLifetimeStat"/>
/// </summary>>
public static void UpdateLifetimeStat(string statName, int value)
{
var stat = _lifetimeStats.GetType().GetField(statName);
stat.SetValue(_lifetimeStats, (int)stat.GetValue(_lifetimeStats) + value);
}
And here's a snippet of the LifetimeStats struct:
public struct LifetimeStatistics {
public int TotalMinutesPlayed;
public int TotalNumberOfJumps;
public int TotalNumberOfDeaths;
public int TotalDistanceTraveled;
public int CurrentDailyPlayStreak;
... other fields, constructors, etc...
}
Anyone have an idea of why the field values aren't updating?
This is because LifetimeStatistics is a struct and is being boxed. Try this:
public static void SetLifetimeStat(string statName, object value)
{
//without SetValueDirect (older versions of Unity don't support SetValueDirect)
var stat = _lifetimeStats.GetType().GetField(statName);
object copy = _lifetimeStats;
stat.SetValue(copy, value);
_lifetimeStats = (LifetimeStatistics)copy;
//with SetValueDirect
var stat = _lifetimeStats.GetType().GetField(statName);
stat.SetValueDirect(__makeref(_lifetimeStats), value);
}
However I don't think you should be using reflection here. Reflection is slow, and in this case you have no way of knowing what stats are available for the user calling the functions besides also possibly not using the right type for value. Ignoring the issue of mutable structs, something without reflection which essentially does the same thing would be to use enums like so:
void SetStat(StatEnum enum, object value)
{
//use a switch and set corresponding value
}
However I would also not recommend this. You still have the same issue of not knowing if you have the correct type for value.
If you only need to get the value outside of the struct you can also make them properties and give them a private set but public get.
Think of what you're trying to gain by not directly accessing the fields that you want to be changed and accessed from outside.

How to create a generic class that can take many parameters

Okay, so I am creating a Utility AI framework. For this to work I need a class that can change a lot depending on the situation I am sure, and I hope that there is a way to use polymorphism or some sort of design pattern to solve my issue.
Let me show you what I mean
I have an action for the sake of example let's say I have the following action Attack Target
This action can have a number of considerations that will vary a lot but all implement the same interface:
public interface IConsideration
{
/// <summary>
/// A unique named identifier for this consideration.
/// </summary>
string NameId { get; }
/// <summary>
/// The weight of this consideration.
/// </summary>
float Weight { get; set; }
/// <summary>
/// If true, then the output of the associated evaluator is inverted, in effect, inverting the
/// consideration.
/// </summary>
bool IsInverted { get; set; }
/// <summary>Calculates the utility given the specified context.</summary>
/// <param name="context">The context.</param>
/// <param name="value"></param>
/// <returns>The utility.</returns>
float Consider<T>(BaseAiContext context, T value);
}
The above is my current implementation it doesn't really solve the issue I have
As you can see the "most" important method of this interface is the Consider
and here lies the issue preferably I should be able to pass data to this class in a way that I can control.
For the sake of example let's say one consideration I have is Move To Location here I want to send the following parameters:
Location of target
Weapon type (ranged / melee)
location list
The above is just an example to prove my point. There is another issue with this - how can I pass the correct parameters when I finally have them? say that I have the following code:
public List<IConsideration> considerations;
float targetDistance = 2;
for (int i = 0; i < considerations.Count; i++)
{
float AxisScore = considerations[i].Consider(BaseAiContext,targetDistance );
}
Since I have to use the Interface type I am unable to know exactly which values to parse as parameters.
To sum it up:
How can i "parameterize" my class in a generic way?
How can I distinguish these parameterizations so I can provide a consideration with the correct values?
As #MarcRasmussen requested an example
As each implementation of your interface might consume different sets of arguments one way to solve it would be to kind of have key-value storage like a dictionary.
There are plenty of improvements to be made like, using ENUMS instead of strings, and having a static manager class for things like that to add/modify/remove settings.
This is a quick example and not tested, with the information available.
public class MoveToTarget : IConsideration
{
//method is changed to have generic return type and accept dictionary for settings
float Consider(BaseAiContext context, Dictionary<string,object> settings){
//make sure required keys exist
if(!settings.ContainsKey("DESTINATION"))
throw new ApplicationException("Missing key DESTINATION");
if(!settings.ContainsKey("SPEED"))
throw new ApplicationException("Missing key SPEED");
// retrieve you required settings, at this stage since you cast an object, you should check the type ... this problem would be solved if you have (as further below mentioned) a specific settings class for all your implementations. this way you ensure type safety too.
Point destination = (Point)settings["DESTINATION"];
float speed = (float)settings["SPEED"];
// and perform whatever logic you need. etc.
}
}
public List<IConsideration> considerations;
//this should be probably static and globally available (?) probably better to have a singleton manager class to deal with that.
Dictionary<string,object> Settings = new Dictionary<string,object>()
{
{"SPEED", 1.0f},
{"RANDOM", new Random()},
{"DESTINATION", new Point()},
{"XYZ", "XYZ"},
//etc.
}
//use foreach unless you need to have access to the index
foreach(var consideration in considerations)
{
float AxisScore = consideration.Consider(BaseAiContext, Settings);
}
some other improvements could be to have a specific settings class for each of your implementations like MoveToTargetSettings and then instead of havin ambiguous "KEYS" in a dictionary you can retrieve the specific settings by its class etc. like var settings = settingDictionary["MoveToTargetSettins"] as MoveToTargetSettings
I think for anything better more details are required, happy to discuss and answer any further questions outside of SO as that will be off-topic :)

Deserialize XML element presence to bool in C#

I'm trying to deserialize some XML from a web service into C# POCOs. I've got this working for most of the properties I need, however, I need to set a bool property based on whether an element is present or not, but can't seem to see how to do this?
An example XML snippet:
<someThing test="true">
<someThingElse>1</someThingElse>
<target/>
</someThing>
An example C# class:
[Serializable, XmlRoot("someThing")]
public class Something
{
[XmlAttribute("test")]
public bool Test { get; set; }
[XmlElement("someThingElse")]
public int Else { get; set; }
/// <summary>
/// <c>true</c> if target element is present,
/// otherwise, <c>false</c>.
/// </summary>
[XmlElement("target")]
public bool Target { get; set; }
}
This is a very simplified example of the actual XML and object hierarchy I'm processing, but demonstrates what I'm trying to achieve.
All the other questions I've read related to deserializing null/empty elements seem to involve using Nullable<T>, which doesn't do what I need.
Does anyone have any ideas?
One way to do it would be to use a different property to get the value of the element, then use the Target property to get whether that element exists. Like so.
[XmlElement("target", IsNullable = true)]
public string TempProperty { get; set; }
[XmlIgnore]
public bool Target
{
get
{
return this.TempProperty != null;
}
}
As even if an empty element exists, the TempProperty will not be null, so Target will return true if <target /> exists
Can you explain why you dont want to use nullable types?
When u define an int (as opposed to int?) property in ur poco, it doesnt really represent the underlying xml, and u will simply get the default values for those variables.
IF u assume you wont get empty/null strings or integers with the value 0 in ur xml, youcan used the method Balthy suggested for each of ur properties, or use the method described here
Generally i think its a better idea to create a schema to describe ur xml, and generate classes based on it, while using nullable types, if you really want your classes represent the underlying data.

Why is Parallel.ForEach loop only doing a shallow copy?

I have the following code:
List<List<Material>> materialCombos;
Parallel.ForEach(materialCombos, combination =>
{
Material material1 = combination[0];
Material material2 = combination[1];
double[] tempValues1 =
material1.MaterialImages
.OrderBy(mi => mi.Time)
.Select(mi => Convert.ToDouble(mi.Temperature))
.ToArray();
});
public class Material
{
[Key]
public int MaterialID { get; set; }
/// <summary>
/// Name of the material.
/// </summary>
public string Name { get; set; }
// other accessors here...
/// <summary>
/// Collection of apparent temperature images with meta-data for this material.
/// </summary>
public virtual ICollection<MaterialImage> MaterialImages { get; set; }
}
It works perfectly fine when using the synchronous foreach loop. However, when I use the parallel version (as above), the MaterialImages object doesn't always copy across to the combination object and when viewing it in the debugger it is null and therefore an exception is thrown in the anonymous function.
Any ideas why this is happening, is it because when it iterates through materialCombos and gets each combination out it does a shallow copy?
Your original post left out the fact that you're using objects from the EF object context. Since that's not thread-safe, you can't do what you want in parallel. It may work to retrieve all the objects and then operate on them concurrently, but I'm not an expert in EF.
You should probably be using a thread safe collection. Switch your type to a ConcurrentBag<ConcurrentBag<Material>> for starters. Also, doesnt look like you are showing what you are doing with the array within the loop (the snippet of code is incomplete)....if you are expecting to access anything you build up within the loop outside of the parralel loop, you will need to make sure that it is also using a thread safe implementation.
What you are probably seeing in the debugger is non-deterministic behaviour due to the threading.

When using a C# property, should the get or the set portion of it massage the underlying data (if there is a need)?

In the code base I was maintaining I found this exact class, pasted below. In logPath property, gets does some work. I would think that it is better to do the work in set - that way it will be done only once. However, partly because this is how the class is written, partly because it is an xml-mapped property, and partly because I am afraid that I might miss something in a debugger, I have doubts.
Additionally, if an element never existed in the xml, and it happened to be optional, then I think I will get a null for the value. I might actually want to differentiate between having no element and receiving empty value. I suppose I can have a private bool member which can help me detect that - that would be an argument for doing work in set rather than get. So, code optimizers work hard these days, so performance is rarely a true concern. It is more of a "figure this out once and do not think about it later" things. This is just one example, and properties frequently do some massaging.
Would you say that it is always better to do work in set? In get? It depends? A mixed style would not bother you a single bit as long as it works?
Thanks.
namespace MyNamespace
{
using System;
using System.Xml.Serialization;
/// <summary>
/// The LoggingListener class encapsulates the "logListener"
/// element of config file, and puts the "logPath"
/// attribute in a file path string.
/// </summary>
public class LoggingListener
{
private string logPathValue;
/// <summary>
/// Gets or sets the LOCAL file path to a log file
/// which will be written during operation of the Updater.
/// </summary>
[XmlAttribute("logPath")]
public string LogPath
{
get
{
return this.logPathValue == null ?
String.Empty : this.logPathValue;
}
set
{
this.logPathValue = value;
}
}
}
}
EDIT: In this given sample ... if the log file is not there, then no logging should take place.
I'd certainly prefer consistency. But the fact is in cases like this it often will not matter. I'm sure the original developer's intent was to avoid the infuriating NullReferenceException bug resulting from attempting to access the LogPath property of some LoggingListener object -- in which case, it probably just seemed most sensible to put the null check in the get (since that's where the exception was thrown).
In general, I'd agree with you that perhaps it makes the most sense to put it in the set -- but then, there's no guaranteeing LogPath will never return null, as the private member could have been set to null from within the class, or perhaps it was never set at all (as Kevin pointed out).
I tend to go with a somewhat hybrid approach: make the property read-only, and make sure it gets set to something non-null in the constructor:
public class LoggingListener {
private readonly string _logPath;
public LoggingListener(string logPath) {
_logPath = logPath ?? string.Empty;
}
public string LogPath {
get { return _logPath; }
}
}
Whether this is an acceptable compromise obviously depends on your specific needs. Also, whether the property should really never be null after all is certainly debatable, depending on the scenario, as you've already remarked.
I personally don't like when property changes assigned value in either get or set accessor. It changes expected property behavior:
var value = null;
var listener = new LoggingListener();
listener.LogPath = value;
if(listener.LogPath != value)
{
// how could we get here?
}
Instead, I prefer to clearly decide, whether property can accept null or not. If it can, it shouldn't do any work in get/set, if yes, it should neither return null nor accept it as a value.
If there is no way to prevent assignment of null, than i would prefer to handle this case in set accessor.
With getters and setters I follow a few rules:
No side effects - don't modify 'B' when you put a value in 'A'
What I put in 'A' comes out of 'A', if you need to modify 'A' expose a new read-only property
If you don't like my value for 'A', tell me now not later when I call a method
Outside of a data model, do not accept or return null
For your example I prefer seeing the following:
public class LoggingListener
{
private string logPathValue = String.Empty;
[XmlAttribute("logPath")]
public string LogPath
{
get { return logPathValue; }
set
{
if(value == null) throw new ArgumentNullException();
this.logPathValue = value;
}
}
}
Yet it's clear to me why you ask, it really about the behavior of "XmlAttribute" and the XmlSerializer. You can use the "DefaultValueAttribute" from the ComponentModel namespace, or use an XSD to provide the defaults, or expose a new property and/or method. You could also try creating an interface to separate concerns, something like the following:
public class LoggingListener : ILogListenerSettings
{
private string logPathValue;
[XmlAttribute("logPath")]
public string LogPath
{
get { return logPathValue; }
set { logPathValue = value; }
}
string ILogListenerSettings.FullLogPath
{
get
{
string path = logPathValue;
if(String.IsNullOrEmpty(path))
path = Environment.CurrentDirectory;
path = Path.GetFullPath(path);
Directory.Create(path);
return path;
}
}
}
the only way to be sure that logPathValue is initialized is to do it yourself...
public class LoggingListener
{
private string logPathValue = string.Empty;

Categories