Modifying Reference to Object to Avoid Protected Setter - c#

I have an abstract class that is generic like so:
class AbstractClass<T>
{
public T Data {get; protected set;}
}
In all cases T is an IEnumerable. In most cases its a List. But in a special case T can be a string, which is a collection of chars. What is the best way to permit Data to be modified when T is a string?
My thought is to simply get the value of Data, then assign it a new value;
var data = Obj.Data;
data = "string";
Will that do what I expect? Are there any pitfalls? Is there a better way?
Edit:
The underlying reason the setter is protected is because it is most often a collection, and the intent is to new the collection in the constructor. Secondly, and I probably should have added this, the Data object is optionally a INotifyPropertyChanged. There is some boilerplate code in the rest of the class, but the basic premise is that I don't want to worry about tracking the assignment of Data in the notifications.
class Concrete<T> : AbstractClass<T>
{
public Concrete(T t)
{
Data = t;
}
}
string str = "String";
Concrete<string> blah = new Concrete<string>(str);
Console.WriteLine(blah.Data); // "String"
string temp = blah.Data;
temp = "Assign";
Console.WriteLine(blah.Data); // "Assign"
I want the last line to print "Assign", but it prints "String". Is there a way to accomplish this without changing the protection? I'm thinking in terms of C++ where the address could just be modified.

C# strings are immutable so you can't just edit them like a collection.
However, there are other classes that can be used as mutable strings. I will be using System.Text.StringBuilder.
Instead of giving a generic argument of string, give it StringBuilder:
string str = "String";
var blah = new Concrete<StringBuilder>(new StringBuilder(str));
Console.WriteLine(blah.Data); // "String"
// to change the string to "Assign", call Clear() then Append()
blah.Data.Clear();
blah.Data.Append("Assign");
Console.WriteLine(blah.Data);

If you really want to do this, you could use the ref keyword. Since c# 7, you can also use ref for returning values from a function, see:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#reference-return-values
However, just because you could, doesn't mean you should. There is probably something wrong with your design if you have to do this.

Related

Is there a way to construct a deeply nested Dictionary with nice syntax and IntelliSense support?

I am trying to create an object that contains the parsed register values of a robot. I have an ASCII text file that contains representations of the variables and arrays. However, I am struggling to think of an easy way to use the deeply nested values. Ideally, the syntax to use the deeply nested objects would be something like Registers["PositionRegister"]["CurrentPosition"]["X_Coordinate"] and the dictionary would be something like this:
(There was a JSON representation here of what I wanted the dictionary to look like, but people kept suggesting JSON serialization...)
However, since I am parsing the file and constructing the object at the same time, I don't know how deep the nesting will go until the parsing is complete.
I've tried using a simple Register class that can contain a dictionary of sub-Registers:
public class Register
{
public Dictionary<string, Register>? subRegisters;
public string name { get; set; }
public string value { get; set; }
}
However, the usage turns into super unintuitive syntax like motionRegister.subRegisters["Register1"].subRegisters["SubRegister1"].subRegisters["Value1"].Value and I'm duplicating information by using the name as the key.
I've also tried using only nested Dictionaries like:
public Dictionary<string, object> CreateRegisters()
{
Dictionary<string, object> TopLevelRegisters = new();
Dictionary<string, object> SubRegisters = new();
Dictionary<string, object> SubSubRegisters = new();
SubSubRegisters.Add("SubSubElement1", "5678");
SubRegisters.Add("SubElement1", "1234");
SubRegisters.Add("SubElement2", SubSubRegisters);
SubRegisters.Add("SubElement3", "1357");
TopLevelRegisters.Add("Register1", SubRegisters);
return TopLevelRegisters;
}
but they end up being super difficult to use since IntelliSense doesn't know what the object will be until runtime. I would return it as another Dictionary, but I don't know how deep the nesting will have to go.
I'm sure that there's a simple solution, but I can't seem to find it.
The closest thing I could come up with is to
Subclass Dictionary<>, and define the subclass in terms of itself (allows for arbitrary depth, and prevents the need for what you call the "unintuitive syntax" of a sub-dictionary manifesting in the path)
Hide the existing indexer with a new implementation (allows for auto-construction of a new level)
Provide a Value property for storing the value of the leaf node.
Provide a ToString() that returns Value (allows for the elimination of .Value from the syntax in certain cases, such as concatenation of strings, WriteLine, etc.)
NOTE: A Name property is dropped altogether because the name can be determined based on the dictionary key.
This code will look something like this
public class RecursiveDictionary : Dictionary<string, RecursiveDictionary>
{
public string? Value { get; set; }
public override string? ToString() => Value;
public new RecursiveDictionary this[string key]
{
get
{
if (!TryGetValue(key, out var subDictionary))
base[key] = subDictionary = new RecursiveDictionary();
return subDictionary;
}
set => base[key] = value;
}
}
During parsing, you only have to output each path to a terminal Value or if you keep track of where you're at in the parsing, simply set the Value of the current (sub)dictionary. (Side note, it doesn't matter how you build it or whether the source is proprietary (your case), JSON, or some other format).
Here's an example construction:
var rd = new RecursiveDictionary();
rd["x"].Value = "Hi!";
rd["x"]["y"].Value = "VALUE";
rd["a"]["b"]["c"]["d"].Value = "VALUETWO";
Notice, I didn't have to allocate RecursiveDictionary for every level; this is because the get portion of the indexer does that for me.
From the static Intellisense (i.e. while program is not running), you can hover over rd and see it is a RecursiveDictionary,
hover over Value and see that it is a string,
and hover over one of the ] or [ and see that it is an indexer on the dictionary:
Now for the dynamic (runtime under debugger) I'm not going to show all the code for various accesses or the Intellisense for it, but I can emulate both in a watch window. What you see in the watch window below could just as easily been lines of Console.WriteLine(...) with you hovering over the various locations. So imagine these examples:
CAVEAT: The ToString() might give you some unexpected results depending on the situation. Are you concatenating strings, are you viewing in the debugger, are you using in a WriteLine(), are you passing a sub-dictionary to another method, etc. If that becomes problematic, then go for a slightly less terse syntax that requires you to always get the value explicitly via the Value property.

Changing one property in multidimensional array changes other array's properties too

I have a multidimensional array called SensorGetResult. In some cases this array can have a single array in it. If that happens, I must copy this one array and add it again, so I must have 2 arrays now. Then I need to change these array's dateTime property. This is my code:
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
sensorGet.SensorGetResult[0].dateTime = end; //It works correctly including this line
sensorGet.SensorGetResult[1].dateTime = start; //At this line both array's dateTime property changes
Why can't I assign dateTime properties to each array individually?
It looks like you are using a reference type for your helperArray.
When the following code executes:
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
What actually happens is you take a the first element of SensorGetResult which is a reference to the object (which I believe you intend to copy) and append the reference to the list thus resulting in a list which has two references to the same object in the memory.
If you want it to make a copy of the object, you have to implement that by yourself. Usually this means creating a new object of the same type and copying all the properties.
var objectToCopy = sensorGet.SensorGetResult[0];
var helperArray = new WhatEverTypeIsYourHelperArray {
Property1 = objectToCopy.Property1,
Property2 = objectToCopy.Property2,
// etc.
};
sensorGet.SensorGetResult.Add(helperArray);
But you have to be aware if any of the properties is furthermore a reference type, you need to do this recursively for all the properties.
If WhatEverTypeIsYourHelperArray is type you own, you could utilize Object.MemberwiseClone method and make it all easier for yourself. You can do this by implementing a method like the following. As a note, MemberwiseClone is a protected method hence the need of a new method in your class.
public WhatEverTypeIsYourHelperArray Clone() {
return (WhatEverTypeIsYourHelperArray)this.MemberWiseClone();
}
But even the MemberwiseClone() method doesn't copy reference types for you, rather just copies the pointers to the objects which means that all the properties of reference type of both the original and the cloned object will point to the same objects in the memory.
SensorGetResult row seems to be a reference type.
So when you wrote
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
you actually said that new row in SensorGetResult will point to the same object as the first one.
You can implement method like below:
public SensorGetResultRow Clone()
{
return new SensorGetResultRow (this.field1, this.field2, etc...)
//or if you use parameterless constructor
return new SensorGetResultRow ()
{
field1 = this.field1
//etc.
}
}
and use it:
var helperArray = sensorGet.SensorGetResult[0].Clone();

Factory to create AND instantiate object, based upon a string?

I have a request to read string messages from a queue and "process them". Each message has a 4 digit "identifier/key" a the start, followed by date, time and another number...from then on, each message is different and requires different processing.
My thought was to use a factory to create an object of the required type and ALSO call the asbtract constructor at the same time.
Is this a sensible approach to take?
If so...how?
e.g.
1000,2013-02-13,09:00:00,492,....................
4000,2013-02-13,09:00:01,492,....................
1000,2013-02-13,09:00:02,74664,....................
4003,2013-02-13,09:00:03,1010,....................
4000,2013-02-13,09:00:04,493,....................
To build object of classes
Message1000 : AbstractMessage, IMessageThing
Message4000 : AbstractMessage, IMessageThing
Message4003 : AbstractMessage, IMessageThing
Where AbstractMessage contains a default constructor and properties for key, date, time, number etc.
If it makes sense depends on your requirements.
You could analyse the string like this:
// inside your actual factoryMethod...
var lines = ...;
foreach(var line in lines)
{
var tokens = line.Split(',');
// for split: you can also specify the max. amount of items if the ..... part can
// consist of more the dots.
CreateMessageObject(tokens); // eventually add to list of AbstractMessage or whatever
}
static FactoryClassConstructor()
{
_typeMap = new Dictionary<string, Type>();
_typeMap.Add("Message1000", typeof(Message1000));
// todo: add other message types
// you also could write a method which will use the class name of the
// type returned by typeof(XYZ) to assure the correct value as key
}
private Dictionary<string, Type> _typeMap;
private AbstractMessage CreateMessageObject(string[] tokens)
{
// simple error checking
if(tokens.Count != 5)
// todo: error handling
return null;
var type = typeMap[tokens[0]];
var instance = Activator.CreateInstance(type);
instance.Date = DateTime.Parse(tokens[1]);
instance.Time = DateTime.Parse(tokens[2]);
// todo initialize other properties
}
Of course you still need to do some error handling but I hope I could give you a good starting point.
The reason why i would use a dictionary is performance. Activator.CreateInstance is not very fast and the lookup with Type.GetType is also slow.
Instead of using the type as Value in the Dictionary you could also use something like this:
Dictionary<string, Action<IMessageThing>> _factories;
_factories = new Dictionary<string, Action<IMessageThing>>();
_factories.Add("Message1000", () => new Message1000());
and to create your object you could call:
var instance = _factories["Message1000"]();
Yes you can and is a correct and sensible approach. The things change a little if you can have a default constructor or not, and changes too if constructor will differ from one concrete implementation to the other. The simplest approach is to have a parameterless constructor.
With this prerequisite you can have something like this:
Type t = Type.GetType(string.Format("Handlers.MyHandlers.Message{0}",messageType));
var handler = Activator.CreateInstance(t) as IMessageThing;
In order to pass the string to the message, you can have a function defined in the IMessageThing interface, lets call it Init that you call immediately after the message creation, or probably better, have a costructor taking a string in the AbstractMessage class, and call it in the activator like this:
var handler = Activator.CreateInstance(t,body) as IMessageThing;
In the constructor of AbstractMessage call an abstract function Init(string body), so each concrete message need to implement its own parser.
Add some more error handling, and you have done.
One way is to split the string on , but set the max count to say 5, this should group all the values AFTER the number as one value:
var parts = your_string.split(new char[] {','},5);
Then you just need to use Activator.CreateInstance() to create your message instance. For example:
Type type = Type.GetType(String.Format("Message{0}",parts[0]));
var instance = Activator.CreateInstance(type) as IMessageThing;
You can then fill out the rest of the properties from parts.
You can either pass each message to a handler, the handler will check if it can handle this type of message. If so it will parse and return some object, otherwise it will return e.g. null and you will know to ask a different handler.
Or you build a parser that knows about the initial part that follows a common format, and then use a lookup table to find a specific message handler that will parse the remaining message and instantiate the correct type. (Pass the common parts to its constructor).
I don't understand what you mean with "create an object of the required type and ALSO call the asbtract constructor". There is no such thing as an abstract constructor. If you mean a constructor of an abstract base class, it is inevitable that it will get called when a subclass is instantiated.

pass by reference and not returning a value

Let's say I have a method that calls another method with some parameters, something like this:
public void SomeMethod()
{
List<SomeObject> TheList = SomeQueryThatReturnsTheList();
TheList = DoSomeWorkWithList(TheList);
}
public List<SomeObject> WorkForList(List<SomeObject> TheListAsParameter)
{
foreach (SomeObject x in TheListAsParameter)
{
....
}
return TheListAsParameter;
}
As you can see, the method WorkForList returns the list it received. My question is this: if I don't return the list and rewrite the signature as public void WorkForList(List<SomeObject> TheListAsParameter) is pass by reference in c# going to mean that TheList in SomeMethod is going to be updated with the work that's done in the WorkForList method? If so, will the following code work the same:
public void SomeMethod()
{
List<SomeObject> TheList = SomeQueryThatReturnsTheList();
DoSomeWorkWithList(TheList);
}
public void WorkForList(List<SomeObject> TheListAsParameter)
{
....
}
Thanks.
Well if you don't use the ref keyword, its address will be passed by value, meaning you will be able to change its element, but you can't initialized it or can't assign it null. for example. If in your method you do:
public void WorkForList(List<SomeObject> TheListAsParameter)
{
TheListAsParameter = null;
}
You will not see the difference in the caller.
You should see this article: Parameter passing in C# by Jon Skeet
In this case, the code will do what you want to do, BUT bear in mind two things:
C# is "pass by value" language. It passes the address of the object, so this will only work if you work with this instance, not change the instance itself. For that, you should use ref keyword, but that usually ends up with harder to read code.
returning objects vastly improves readability - what you do is considered a side-effect, a user of your method (another team member maybe) may not be aware you are modifying the list contents.
Yes, you can do that. But returning the object might be useful, for clarity, and to allow methods chaining.
For example with your first WorkForList method :
yourObject.WorkForList(list).DoSomethingWithTheReturnedList();
Yes - this should behave exactly as you've described... Surely you can just test the code you've already written?
Yes, as long as your WorkForList() method doesn't have a line like this:
TheListAsParameter = something;
then any changes you make to TheListAsParameter will be reflected in the calling method without returning it.
To speak precisely here, in this case you aren't passing a variable by reference. You are passing a reference type by value. Pass by reference involves the use of the ref keyword in C#.
As long as you don't use foreach to modify values of the list:
foreach (SomeObject x in TheListAsParameter)
{
....
}
As you are not allowed to modify the contents of a Collection you are walking through using foreach.

What is the best way to store static data in C# that will never change

I have a class that stores data in asp.net c# application that never changes. I really don't want to put this data in the database - I would like it to stay in the application. Here is my way to store data in the application:
public class PostVoteTypeFunctions
{
private List<PostVoteType> postVotes = new List<PostVoteType>();
public PostVoteTypeFunctions()
{
PostVoteType upvote = new PostVoteType();
upvote.ID = 0;
upvote.Name = "UpVote";
upvote.PointValue = PostVotePointValue.UpVote;
postVotes.Add(upvote);
PostVoteType downvote = new PostVoteType();
downvote.ID = 1;
downvote.Name = "DownVote";
downvote.PointValue = PostVotePointValue.DownVote;
postVotes.Add(downvote);
PostVoteType selectanswer = new PostVoteType();
selectanswer.ID = 2;
selectanswer.Name = "SelectAnswer";
selectanswer.PointValue = PostVotePointValue.SelectAnswer;
postVotes.Add(selectanswer);
PostVoteType favorite = new PostVoteType();
favorite.ID = 3;
favorite.Name = "Favorite";
favorite.PointValue = PostVotePointValue.Favorite;
postVotes.Add(favorite);
PostVoteType offensive = new PostVoteType();
offensive.ID = 4;
offensive.Name = "Offensive";
offensive.PointValue = PostVotePointValue.Offensive;
postVotes.Add(offensive);
PostVoteType spam = new PostVoteType();
spam.ID = 0;
spam.Name = "Spam";
spam.PointValue = PostVotePointValue.Spam;
postVotes.Add(spam);
}
}
When the constructor is called the code above is ran. I have some functions that can query the data above too. But is this the best way to store information in asp.net? if not what would you recommend?
This is a candidate for an immutable struct that "looks like" an enumeration:
(Also, I noticed you used the same id value for two of them, so I fixed that...
You can use the following just as you would an enumeration...
PostVoteTypeFunctions myVar = PostVoteTypeFunctions.UpVote;
and real nice thing is that this approach requires no instance storage other than a 4-byte integer (which will be stored on stack, since it's a struct). All hard-coded values are stored in the type itself... of which only one will exist per AppDomain...
public struct PostVoteTypeFunctions
{
private int id;
private bool isDef;
private PostVoteTypeFunctions ( ) { } // private to prevent direct instantiation
private PostVoteTypeFunctions(int value) { id=value; isDef = true; }
public bool HasValue { get { return isDef; } }
public bool isNull{ get { return !isDef; } }
public string Name
{
get
{ return
id==1? "UpVote":
id==2? "DownVote":
id==3? "SelectAnswer":
id==4? "Favorite":
id==5? "Offensive":
id==6? "Spam": "UnSpecified";
}
}
public int PointValue
{
get
{ return // Why not hard code these values here as well ?
id==1? PostVotePointValue.UpVote:
id==2? PostVotePointValue.DownVote
id==3? PostVotePointValue.SelectAnswer:
id==4? PostVotePointValue.Favorite:
id==5? PostVotePointValue.Offensive:
id==6? PostVotePointValue.Spam:
0;
}
}
// Here Add additional property values as property getters
// with appropriate hardcoded return values using above pattern
// following region is the static factories that create your instances,
// .. in a way such that using them appears like using an enumeration
public static PostVoteTypeFunctions UpVote = new PostVoteTypeFunctions(1);
public static PostVoteTypeFunctions DownVote= new PostVoteTypeFunctions(2);
public static PostVoteTypeFunctions SelectAnswer= new PostVoteTypeFunctions(3);
public static PostVoteTypeFunctions Favorite= new PostVoteTypeFunctions(4);
public static PostVoteTypeFunctions Offensive= new PostVoteTypeFunctions(5);
public static PostVoteTypeFunctions Spam= new PostVoteTypeFunctions(0);
}
It is difficult to tell from the fragment of code you have posted whether you expose any of the data outside the class.
If not, then this would work. However, if not, there are several issues:
If you are exposing the List, you should only ever return a copy of it as an IEnumerable<PostVoteType> using the yield keyword.
Make sure your PostVoteType is immutable, otherwise the references can be changed and the fields used might be altered
Looking at your code, it looks like you're just trying to create a set of objects that really just put the enum PostVotePointValue into some sort of list. I.e. you already have what you need defined in just the enum itself. I would encourage you to not define the same information in two places (this data store you are asking for and the enum). This is common mistake I see people make. They create a lookup table/list, then create an enum that mirrors the rows of the table and that means they have to modify two places for any change to the list.
If PostVotePointValue isn't an enum but just some constants or if there is more info you are planning on packing in, then this isn't relevant.
Here's some examples of how to work with Enums as 'lists' from http://www.csharp-station.com/Tutorials/Lesson17.aspx
// iterate through Volume enum by name
public void ListEnumMembersByName()
{
Console.WriteLine("\n---------------------------- ");
Console.WriteLine("Volume Enum Members by Name:");
Console.WriteLine("----------------------------\n");
// get a list of member names from Volume enum,
// figure out the numeric value, and display
foreach (string volume in Enum.GetNames(typeof(Volume)))
{
Console.WriteLine("Volume Member: {0}\n Value: {1}",
volume, (byte)Enum.Parse(typeof(Volume), volume));
}
}
// iterate through Volume enum by value
public void ListEnumMembersByValue()
{
Console.WriteLine("\n----------------------------- ");
Console.WriteLine("Volume Enum Members by Value:");
Console.WriteLine("-----------------------------\n");
// get all values (numeric values) from the Volume
// enum type, figure out member name, and display
foreach (byte val in Enum.GetValues(typeof(Volume)))
{
Console.WriteLine("Volume Value: {0}\n Member: {1}",
val, Enum.GetName(typeof(Volume), val));
}
}
}
You should be able to adapt the above into an approach that will give you a list that you can use for databinding if you need it.
I am wondering why you could not just use a simple enum for this?
public enum PostVoteType
{
UpVote = 0,
DownVote = 1,
SelectAnswer = 2,
Favorite = 3,
Offensize = 4,
Spam = 5
}
"Never" is a very hard word indeed.
In your particular case you are asserting that not only is your PostVoteType data absolute and immutable, but so is the container collection. Frankly I don't believe you can know that, because you are not the business (your interpretation of requirement is imperfect) and you are not psychic (your knowledge of the future is imperfect).
I would suggest that you always store any data which cannot be expressed as an enumeration in some kind of repository. Where you expect relational and/or transactional and/or mutable needs that means a database, if you expect high read to write ratio that can be a config file (which I believe this case should be).
Edit: In terms of memory persistance I agree with others that the cache is the best place to store this, or rather in a domain object which is backed by cache.
Aside: your construction of PostVoteTypes is horrible - strongly suggest you want a refactor :)
If it doesn't change, is commonly accessed, and is the same for all users, then the .NET cache is the proper place. Have a property that yields these values. Inside, the property checks the cache for this list and returns the stored value; otherwise, it constructs it from scratch, adds to the cache, and returns the value.
This should still probably be configured in the database though, even if you cache it. I imagine that you'll need to use these value in conjunction with other data in your DB.
When you need to often access the same data, and need not to store it into the underlying database, and that this data is about the same in every situation the application may encounter, then I suggest to use caching. Caching is born from these requirements. Caching is normally the fastest way to providing data as they are always kept in memory or something similar to ease and to make the access easier by the application.
Here is a nice caching tool provided with Microsoft Enterprise Library, the Caching Application Block.
I think it is worth to take the time to learn how to use it effectively.
create a singleton class.

Categories