I have an object that represents the current event that is taking place. This event contains a lot of settings. What is the best practice for storing all setting variables inside the event object?
The settings are stored in a database (right now in different columns based on the base class: ValueString, ValueInt, ValueBool, ValueDateTime, ValueFloat, ValueDecimal). A unique key represents the setting in the database.
As soon as i have loaded the events object i will store it in the local cache for quick access.
Should i cast everything to object? (Feels like un-needed casts to get/set settings)
class Event
{
// string = settings key
Dictionary<string, object> _settings;
public void AddSetting(string key, object value)
public object GetSetting(string key)
}
or should i have it in different dictionaries?
class Event
{
// string = settings key
Dictionary<string, string> _settingStrings;
Dictionary<string, int> _settingInts;
...
public void AddSetting(string key, string value)
public void AddSetting(string key, int value)
...
public string GetStringSetting(string key)
public int GetIntSetting(string key)
...
}
Any ideas?
You can store everything as an Object, but rather than performing a straight cast, use generics to build an easy to use API:
private IDictionary<string,object> _settings = new Dictionary<string,object>();
public void AddSetting<T>(string key, T value) {
_settings[key] = value;
}
public T GetSetting<T>(string key, T notFound = default(T)) {
object res;
if (!_settings.TryGetValue(key, out res) || !(res is T)) {
return notFound;
}
return (T)res;
}
The cast remains there, but the API hides it from the user: now the user can safely write
string searchPath = settingContainer.GetSetting<string>("searchPath");
int retryCount = settingContainer.GetSetting<int>("retryCount", -1);
I really do like dasblinkenlight's answer.
Except instead of wasting one column for each datatype, I would rather have only one column (likely a VARCHAR) on your datatable.
Advantages of this:
Faster reading (Only one indexed column)
Saving up storage (Only one varchar per row)
And then you can either use generics as mentioned, or cast the string object in your implementation to your wished type.
Related
I have a class with predefined constant strings which are used as keys to retrieve the data from the external storage by provided key.
public class StorageKeys
{
public const string SomeKey = "Foo";
public const string AnotherKey = "Foooo";
}
public interface IStorage
{
string GetValue(string key);
}
Which is used like this:
IStorage t = new Storage();
string value = t.GetValue(StorageKeys.SomeKey);
It works but I'm concerned that potentiality it's possible to call GetValue method with just string argument which can cause an error:
string value = t.GetValue("Illegal key");
That's why I've come up with this idea:
public class StorageKeys
{
public static StorageKeys SomeKey = new StorageKeys("Foo");
public static StorageKeys AnotherKey = new StorageKeys("Foooo");
private StorageKeys(string key)
{
_key = key;
}
private readonly string _key;
public static implicit operator string(StorageKeys key) => key._key;
}
public interface IStorage
{
string GetValue(StorageKeys key);
}
After these changes my method can be used only with correct keys but I think it would decrease a performance because of static properties and implicit casting.
So my question is it a good idea?
Am I overconcerned?
How much slower my second approach would be comparing to the first one?
Is there another way to prevent passing wrong arguments?
Am I overconcerned?
Short answer, yes.
What you are trying to do is prevent passing an invalid argument which isn't what you are supposed to do in the first place, you should consider using an enum IF that is possible, that makes it 99.9% typesafe and almost no checks would be required.
In a situation where you need that param to be a string, just perform a validation in GetValue(string key) and either return a null if you wish to handle that later or just throw an Exception.
C# 3 btw...
So I am working on my AI blackboard. Part of that is an associative map, of string names to a gerneric values (object), right now the value is stored as a boxed value type or a string cast to an object.
So something like this:
public class ContextEntry
{
public string name;
public object value;
}
public class BehaviorContext
{
public ContextEntry AddEntry<T>(string name, T value)
{
//checks to see if T is an allowed type, create a ContextEnetry
//and adds it to map, returning a reference to the added entry
}
public bool GetValue<T>(string name, ref T val)
{
//look for entry, if found, do an as check with T,
//and then unbox the entry value into T
//otherwise return false
}
public bool GetValue(string name, ref object val)
{
//same as GetValue<T> but with object instead
}
public bool SetValue<T>(string name, T val)
{
//look for entry, if found, do an as check with T,
//and then box T into the entry value
//otherwise return false
}
public bool SetValue(string name, object val)
{
//same as SetValue<T> but instead checks val type is compatible with entry
}
protected Dictionary<string, ContextEntry> m_EntryMap = new Dictionary<string, ContextEntry>();
}
For those adding entries, they can keep a copy of ContextEnty around and directly access the value from there.
So what I am seeing is the constant boxing and unbox is hurting me, when it comes to frame time, as this is used alot.
I was wondering if doing something like this for ContextEntry would be better.
public interface IContextEntry
{
string Name {get; set;}
bool SetObj(object o);
void GetObj(ref object o);
}
public class ContextEntry<T> : IContextEntry
{
public bool SetObj(object o) { //do a compatibility check then unbox into value }
public void GetObj(ref object o) { //box value into o }
public T value;
}
Now i would keep a seperate dictionary of ContextEntry[T] per allowable type, and only search in right one if some one used GetValue[T] or SetValue[T]. If someone uses GetValue or SetValue, i would also keep a dictionary of IContextEntry with all entries. A user would use the templated versions of the functions often but also the non templated version often as well. When using a the non-templated versions, they would induce a virtual function call as well a boxing/unboxing.
Im wondering if its worth it. Any opinions?
I have a static class which has a private Dictionary. I have written public methods to add and remove objects to it. Now I want to ensure that when I remove one of the items from dictionary, noone else is using it.
How can I achieve this?
Do you mean you want to ensure that no-one else is using the dictionary, or no-one else is using the value which was in the dictionary?
You can solve the first using locking... but you can't really do the second. Someone could fetch a reference to the object from the dictionary and store that reference for as long as they like. There may be a solution if the value is an interface type - you could delegate all calls through an extra "wrapper" class, and invalidate that wrapper class. I can go into more details if you want, but I'm hoping you're really just interested in the first type of safety :)
That can be achieved like this:
private static readonly object mutex = new object();
// Or whatever
private static readonly Dictionary<string, string> map =
new Dictionary<string, string>();
public static void AddEntry(string key, string value)
{
lock (mutex)
{
map[key] = value;
}
}
public static string GetValue(string key, string value)
{
lock (mutex)
{
return map[key];
}
}
Obviously you'll want to tweak how you're using the dictionary.
If you're using .NET 4, another alternative would be to use ConcurrentDictionary which is already thread-safe.
Have a look at using lock Statement (C# Reference)
I have an object, MySession, that has a hashtable for storing arbitrary properties with arbitrary types. The relevant part of the object definition is:
public class MySession
{
private Hashtable _sessionVars;
///
/// Set and retrieve session variables ala the traditional session managers.
/// So, SessionObject["var1"] can be used to set or retrieve a value for var1.
///
/// Name of the variable to access.
/// An object that was stored in the session under key.
public object this[string key] {
get {
if (_sessionVars.ContainsKey(key)) {
return this._sessionVars[key];
}
return null;
}
set {
if (this._sessionVars.ContainsKey(key)) {
this._sessionVars.Remove(key);
}
this._sessionVars[key] = value;
}
}
}
The annoying thing is that I have to properly cast the properties when I want to use them. For example:
MySession session = new MySession();
if ( (bool)session["valid"] == true ) { /* do something fun */ }
I would rather be able to do:
MySession session = new MySession();
if ( session["valid"] == true ) { /* do something fun */ }
Is it possible to do this in C#? If so, how?
Update: I do not want to use explicit methods for accessing the properties. The point is to be able to access them as simply as possible. Not like session.GetProperty(name, type) or something.
If you think carefully, you will realize that this is inherently impossible.
What if you write session[someTextbox.Text]?
What if you assign two different types to the same identifier?
Compiling such code would involve solving the halting problem to figure out what type each string would have.
Instead, you could make a strongly-typed wrapper class around HttpContext.Current.Session with properties that include casts in their getters.
If you are using .Net Framework 4.0 then you can do it by deriving your MySession class from DynamicObject and overriding the necessary methods.
Here is the code:
public class MySession : DynamicObject
{
//Why not use Dictionary class?
private Hashtable _sessionVars = new Hashtable();
public override bool TrySetMember(SetMemberBinder binder, object value)
{
this[binder.Name] = value;
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this[binder.Name];
return true;
}
//You can make it private so that users do not use strings directly.
public object this[string key]
{
get
{
if (_sessionVars.ContainsKey(key))
{
return this._sessionVars[key];
}
return null;
}
set
{
if (this._sessionVars.ContainsKey(key))
{
this._sessionVars.Remove(key);
}
this._sessionVars[key] = value;
}
}
}
And this how you use it:
dynamic ses = new MySession();
ses.number = 5;
ses.boolean = true;
Console.WriteLine(ses.number > 4);
if (ses.boolean)
{
Console.WriteLine(ses.number - 1);
}
Console.ReadKey();
No need for casting or using string to access the new fields! If you are using Resharper you will get intellisense for existing fields too. If you need more functionality you can override other members too.
I personally end up having to handle the scenario where the session variable hasn't been set yet. Therefore, I end up with a method that looks like this:
public class MySession
{
...
public T GetValue<T>(string key, T defaultValue)
{
return _sessionVars.ContainsKey(key) ? this._sessionVars[key] as T : defaultValue;
}
}
Then T can be inferred. It can then be called like this (no casting required):
if (mySession.GetValue("valid", false))
{
// fun stuff here
}
I'm not really sure is "as T" works. If not, you can cast it to (T) done that before. "as T" would be nice if you've got inherited classes and such.
I typically derive off a class like mySession and call base.GetValue() in property getters I expose off the derived class.
If you're passing string (or any sort of object) keys, then it's impossible to do; the indexer method can only return one specific type, so you couldn't possible have it return a string or a double, for instance.
There are a couple of options: one, if this is a limited-scope class that doesn't need the flexibility of arbitrary keys, then you can just add explicit properties--maybe just for commonly used properties if you want to still be able to fall back on the object-returning indexer.
Or, you could add a generic Get method, like so:
public T GetValue<T>(object key) {
if(_hashSet[key] is T) {
return (T)_hashSet[key];
}
throw new InvalidCastException();
}
That doesn't get you much, though, since you'll still have to specify the type name, you're just moving it from the cast to the generic parameter.
EDIT: Of course, how you want to handle invalid casts is up to you, but throwing the exception mimics the behavior of the direct cast. As someone mentioned in another answer, if you also specify a parameter of type T in the signature, then it will get the correct type from that parameter.
Easy and best way to add session
public static void Add<T>(string key, T value)
{
var current = HttpContext.Current;
if (current == null) return;
current.Session.Add(key, value);
}
Example
public Model User
{
private string searchText
{
get { return SessionHelper.Get<string>("searchText"); }
set { SessionHelper.Add("searchText", value); }
}
}
I'm creating a Settings object in my app, used for storing user-defined settings and whatnot. I plan on using various datatypes for my setting fields (ints, strings, enums, anything Serializable, really).
I'd also like, if possible, a type-safe way to set any of the settings. My proposed method would be doing something like this:
Tuple<string, Type> SettingName = new Tuple<string, Type>("NumberOfFoos",
typeof(**TYPE**));
public void Set(Tuple<string, Type> key, **TYPE** value) { /* Stuff */ }
The Tuple would effectively be the "setting" that the user would push a value to, and would consist of the key for that setting as well as the type of that setting. What I'm wondering is if there's any way to have the compiler enforce that, in the Set() method, the type of value is of the same type as the type object saved in the tuple passed to Set()? Is the way I proposed even possible? Thanks!
EDIT: I thought of some more things I should clarify.
1) This is intended to be a static class, so I won't be able to serialize the whole class, only members in it. Therefore, I'd really like to not have to deal with a serialization for each field. I was planning on storing all the setting values in a Dictionary<string, **TYPE**> and serializing that.
2) The Tuple definitions are meant to be constant and static. I'm really treating them as more of a typedef-type thing (I really should make my own SettingKey struct), which the user passes to Set to indicate what field they are changing. The Type parameter is meant to enforce the the value parameter is of the specified type.
Something like
public void Set<T>(Tuple<string,T> key, T value) { /* stuff */ }
might do it
It's better to get rid of the tuple, and use a generic method:
public void Set<T>(string key, T value);
That way, you can specify the type at compile-time
Set<string>("MyStringKey", "foo");
Set<int>("MyIntKey", 1);
or the compiler can infer it for you:
Set("MyStringKey", "foo");
Set("MyIntKey", 1);
and in Set, you can use typeof(T) to get the Type object you would have passed in.
Why not simply add strongly typed properties to your settings object? e.g. public int NumberOfFoos {get {} set {...}} and in the getter and setter call your common serialization and deserialization code.
If you do this your settings object isn't exposing how it works internally and you have full intellisense support on it.
Well, if you did something like Set<T>(Tuple<string, T>, T value), you'd get what you're after for setting. And I think the compiler could infer the T in Set<T>() at usage, so you would have to write it.
But your Get<T>(), you'd have to specify the type you expected to get back.
public class Foo
{
Tuple<string, Type> SettingName = new Tuple<string, Type>("NumberOfFoos",
typeof(**TYPE**));
public void Set(Tuple<string, Type> key, object value)
{
if(value.GetType() != SettingsName.Value)
throw new ArgumentException("value");
}
}
You would be better of using generics like in the other answers though.
I don't think you need to deal with Types at all. Would something like this be good enough?
class Settings {
public static int Foo {
get { return (int)_map["Foo"]; }
set { _map["Foo"] = value; }
}
public static string Bar {
get { return (string)_map["Foo"]; }
set { _map["Foo"] = value; }
}
// ...
private static Dictionary<string, object> _map =
new Dictionary<string, object>();
}
You'd then serialize the dictionary. You could even use some code-generation to create this class.