I have a class definition in which a readonly member is defined.
private readonly Dictionary<string, string> map = new Dictionary<string, string>();
Now in order to test my design, I want to access this member outside its class definition. I was thinking of providing a get method but unable to write an error free syntax.
Is it possible to assign value to a member(using new) and still able to define its get method?
PS: I am new to C# language.
EDIT:
I have not written the code, its just a statement I have copied from an already written module. I have made some design changes in the module and want to test it with minimal changes possible in the code, so for that I was looking to get the readonly access of this member outside the class.
You can define a read-only property for permitting public access to your field:
private readonly Dictionary<string, string> map =
new Dictionary<string, string>();
public Dictionary<string, string> Map
{
get { return map; }
}
Note that this will only prevent external classes from changing the instance reference assigned to map, not from changing the content of the dictionary itself.
One could argue that you shouldn't write tests for private members of a class. Tests should only use the public interface and don't rely on the internals of the class, since you should be able to refactor internals of the class without breaking any tests.
If you add a public getter 'only for testing' there's no guarantee that someone will start using somewhere in the project.
If you really want to expose the dictionary and use .NET 4.5, use ReadOnlyDictionary class to make sure that the caller won't change anything.
public IDictionary<string, string> Map
{
get { return new ReadOnlyDictionary<string, string>(map); }
}
Just create a simple getter
public Dictionary<string, string> Mapping
{
get { return map; }
}
You mean something like this?
readonly Dictionary<string, string> _map = new Dictionary<string, string>();
public Dictionary<string, string> Map
{
get { return _map; }
}
Why are you making this variable readonly?
If you're trying to give access to the values contained in the dictionary you could create a method that exposes the dictionary without allowing it to be modified:
public string GetMapValue(string key)
{
return _map[key];
}
You could write a public property function to return the private readonly map, e.g:
public Dictionary<string, string> Map { { get { return map; } } }
However, the Dictionary is still mutable. If you want a read-only Dictionary, see this SO question.
Related
I'm making a Phone Book console application in c# and It's my biggest project so far :)
I consider myself as a beginner but I would love to improve
I am using 3 classes to create this, here they are:
Modifications
Search
Display
Modifications class is responsible for adding, deleting and editing contacts. Search and Display classes are self explanatory. I also have interfaces for each of these classes.
Problem:
I created a List of KeyValuePair inside Modifications class, like this:
private List<KeyValuePair<string , int>> AllContacts { get; set; }
public Modifications()
{
AllContacts = new List<KeyValuePair<string, int>>();
}
I would like to access this AllContacts object in my other classes. But I failed to achieve this while maintaining encapsulation. AllContacts is like my main source of data. I add contacts in this List. I don't want someone in my main method to be like modificationObject.AllContacts.Clear();
My Attempts:
[ skip this if you prefer :) ]
My Sad Attempt Part 1:
-Inherited Display Class from base class Modifications
-in my Modifications class, I created a protected property of type List<KeyValuePair<string , int>> and named it 'AllContacts' as a database
-in my Display class , I created a private property of same type as above and named it _allContacts
-inside Constructor of my Display class, I requested a Modification type object named it modObject
-I stated , _data = modObject.AllContacts;
-It didnt work, I presume it's because only derived objects are able to get this property?
My Sad Attempt Part 2:
-Assuming my assumption is true, I tried to downcast the modObject to its derived class type, Display. Got compilation error instead. Tried to make a protected GetAllContacts() method, compilation error.
My Sad Attempt Part 6:
-In end, I just made it a public property with a private setter. My application works, But people could still go x.AllContacts.Clear() in my main method somehow.
Questions:
How can I use AllContactsobject in other classes without breaking encapsulation? Is it even possible?
Initially, I created a separate class for data and I had 3 other classes (Modification, Search and Display) , its a better design, right? I had same problem in accessing that data object in my other classes.
Thanks :)
Additional Context if required: (currently working application , no methods)
Modification class:
public class Modifications
{
public List<KeyValuePair<string, int>> AllContacts { get; private set; }
public Modifications()
{
AllContacts = new List<KeyValuePair<string, int>>();
}
....
Display class:
public class Display : IDisplayable
{
private List<KeyValuePair<string, int>> AllContacts;
public Display(Modifications modificationsObject)
{
AllContacts = modificationsObject.AllContacts;
}
....
You don't need to declare accessors for a private variable member unless you want to disallow the setter for all others methods but it is more speed optimized to use readonly field than property that avoid useless CPU Proc Calls that consume ticks timings for nothing.
To access it from other classes you must declare it as public like that:
public List<KeyValuePair<string , int>> AllContacts { get; private set; }
So others classes can read the reference and invoke variables accessors and methods of the List instance like Count and Add but they can't replace this instance reference and thus change the object itself.
But if you want to disallow manipulating of the list, you may implement all wrapped methods you want to expose like Count, Add, Delete, Remove and so on as well as indexer and you can indicate that the class implements IExumerable<KeyValuePair<string , int>>.
By this way you can have a strong encapsulation:
public class MyClass: IEnumerable<KeyValuePair<string , int>>
{
private readonly List<KeyValuePair<string , int>> AllContacts
= new List<KeyValuePair<string , int>>();
public int ContactsCount
{
get { return AllContacts.Count; }
}
public KeyValuePair<string , int> this[int index]
{
get { return AllContacts[index]; }
set { AllContacts[index] = value; } // don't declare if readonly
}
// if adding is allowed
public int Add(KeyValuePair<string , int> item)
{
...
}
...
}
Honestly,I know I can miss the set clause to avoid user setting my property.
Like below code:
private Dictionary<int, string> _configurations = new Dictionary<TState, StateConfiguration>();
public Dictionary<int, string> Configurations { get { return _configurations; } }
So, we can't run below code at outer code:
XXX.Configurations = new Dictionary<int, string>();
It prompts :
Property or indexer 'XXX.Configurations' cannot be assigned to -- it is read only
But we can change the value like below code:
XXX.Configurations.Add(1,"1000")
Because dictionary is a reference type.
So how can I avoid this. Let user access the reference property with no changing.
You could try returning the dictionary as read-only:
public IDictionary<int, string> Configurations
{
get { return new ReadOnlyDictionary(_configurations); }
}
It sounds like you want to expose a ReadOnlyDictionary. You could create a new one each time the property is accessed, or you could have two fields - one for the writable dictionary (which you never expose) and one for the read-only wrapper.
How do you define a getter and setter for complex data types such as a dictionary?
public Dictionary<string, string> Users
{
get
{
return m_Users;
}
set
{
m_Users = value;
}
}
This returns the entire dictionary? Can you write the setter to look and see if a specific key-value pair exists and then if it doesn't, add it. Else update the current key value pair? For the get, can you return a specific key-value pair instead of the whole dictionary?
Use an indexer property (MSDN):
public class YourClass
{
private readonly IDictionary<string, string> _yourDictionary = new Dictionary<string, string>();
public string this[string key]
{
// returns value if exists
get { return _yourDictionary[key]; }
// updates if exists, adds if doesn't exist
set { _yourDictionary[key] = value; }
}
}
Then use like:
var test = new YourClass();
test["Item1"] = "Value1";
It is not possible to do it in a way that would involve only properties. You theoretically could write a setter, but for a getter, you would need to specify a key that you want to retrieve. That is impossible since properties do not accept parameters. Natural way to accomplish what you want would be to use methods:
private Dictionary<string, string> users = new Dictionary<string, string>();
public void Set(string key, string value)
{
if (users.ContainsKey(key))
{
users[key] = value;
}
else
{
users.Add(key, value);
}
}
public string Get(string key)
{
string result = null;
if (users.ContainsKey(key))
{
result = users[key];
}
return result;
}
Alternatively, as others have already said, you could use indexers, but I've always found them a little cumbersome. But I guess it's just a matter of personal preference.
And just for the sake of completeness, this is how a setter could look like, although it's highly unusual and counter-intuitive to have such a property:
public KeyValuePair<string, string> Users
{
set
{
Set(value.Key, value.Value);
}
}
Internally, it uses the Set method from my previous snippet.
It looks like you want an "named indexer". Here's (my) one way to accomplish that using C#.
My approach exposes a property that returns an object (with a default indexer) which will perform the indexing into the appropriate field given the lambdas to do it.
There are reasons you may or not want to use this method, but I'll leave that to you. :)
You won't be able to do that with a property. You'll need to use methods for that, or add an indexer to your class. The get method can't accept a parameter (the key).
Another option, if you want someone to be able to easily add/remove keys to the dictionary but prevent them from setting an entirely new one would be to make the property a read-only property that returns a dictionary created in the constructor. It would be less flexible then adding get/set methods, but in common, simple cases it can do just fine.
It is possible to do so with the setter but highly unrecommended, and is completely impossible with the getter as it takes no parameter to determine what to get.
For the setter you would have to pass a Dictionary<string, string> with a single pair but it goes against what you would expect the getter/setter to usually do and completely stops you setting the entire Dictionary.
A much better way is to use a pair of methods which you can name Get and Set if you so desire.
Dictionary<string, string> param = new Dictionary<string, string>();
public void SetYourParameter(string parametrName, string paramValue)
{
param[parametrName] = paramValue;
}
public string GetYourParameter(string parametrName)
{
// ContainKey ---> It returns value if the key was found
if( param.ContainsKey(parametrName))
return param[parametrName];
else
return null;
}
Like we do Session.Add("LoginUserId", 123);
and then we can access Session["LoginUserId"], like an Array, how do we implement it?
You need an indexer:
public Thing this[string index]
{
get
{
// get the item for that index.
return YourGetItemMethod(index)
}
set
{
// set the item for this index. value will be of type Thing.
YourAddItemMethod(index, value)
}
}
This will let you use your class objects like an array:
MyClass cl = new MyClass();
cl["hello"] = anotherObject;
// etc.
There's also a tutorial available if you need more help.
Addendum:
You mention that you wanted this to be available on a static class. That get's a little more complicated, because you can't use a static indexer. If you want to use an indexer, you'd need to access it off of a static Field or some such sorcery as in this answer.
You should use indexers
See the link:
http://msdn.microsoft.com/en-us/library/2549tw02.aspx
Sounds like all you need is a generic dictionary.
var session = new Dictionary<string, object>();
//set value
session.Add("key", value);
//get value
var value = session["key"] as string;
If you want to make this static, just make it a static member in another class.
public static class SharedStorage
{
private static Dictionary<string, object> _data = new Dictionary<string,object>();
public static Dictionary<string, object> Data { get { return _data; } }
}
Then you can access it as such, without having to initialize it:
SharedStorage.Data.Add("someKey", "someValue");
string someValue = (string) SharedStorage.Data["someKey"];
If you want to be more adventurous and are using .NET 4 you can also use an Expando Object, like the ViewBag member available to controllers in ASP.NET MVC 3:
dynamic expando = new ExpandoObject();
expando.UserId = 5;
var userId = (int) expando.UserId;
With the way you usually use the Session variable all you really need is a generic Dictionary collection like this one. You don't really need to write a class. But if you need to add extra functionality and/or semantics you could certainly wrap the collection with a class and just include and indexer.
For other collections check out the Collections.Generic namespace.
I have the following in a C# class:
public static readonly SortedDictionary<string, string> Fields =
new SortedDictionary<string, string>
{ ... }
I was hoping there was a way to get Intellisense to provide prompts for all the keys defined in Fields. It supplies lists of the methods and properties in the class, including the Fields property, but when I go to access Fields[ or Fields[", it says nothing other than that I need to supply a string key. Is there a way to have it tell me a list of the string keys since this is a static class property that is not at all dynamic or changed after compilation?
If the keys are static wouldn't you be better off using an enumeration as your key instead of a string?
With an enumeration your compiler can tell you what the options are, but you can't do that with strings.
Do this instead:
public enum MyKeys
{
Key1,
Key2,
Key3
}
public static readonly SortedDictionary<MyKeys, string> Fields =
new SortedDictionary<MyKeys, string>
{ ... }
This will cause intellisense to pick up the enum type so you'll get the desired effect.
It seems to me that you assume that readonly there means that the dictionary won't ever change. This isn't the case - it only means that the value of the field (which is a reference to the dictionary) won't change (and even then it can still change while inside constructor, and can be null before it executes). The dictionary itself is quite mutable.
The best way for you to do this is probably to create public static readonly fields or properties.
If you need dictionary-like behavior, you should make the keys an enum as other people have suggested.
Remember that all of the dictionary class are mutable, which means that other code can add or remove items from your dictionary. The only way to prevent this would be to inherit a ReadOnlyCollection around a KeyedCollection and expose the indexer.
I have used static properties to do this.
What I have done for a Settings class of mine in order to get Intellisense was to create a code snippet that creates a static property. The code snippet is set up so that I enter the name of the setting and that same name is used in both the Property name and the lookup name.
Like this:
<Code Language="CSharp" Kind="method decl">
<![CDATA[ public static string $name$
{
get { return GetSetting("$name$", $default$); }
set { SaveSetting("$name$", value); }
}
]]>
</Code>
The GetSetting method would do something like this:
private static string GetSetting(string name)
{
if (!_Fields.ContainsKey(name))
_Fields.Add(name, default);
return _Fields[name];
}
This makes it really easy to add static properties and still get Intellisense.