Related
I need to sort a list of objects and an arbitrary sort property. If there are multiple objects in my list that have the same value for that sort property, then repeatedly sorting the same list will rearrange the members with the same value of sort property. To be clear, each time sort is run, a new list is generated and the order of members is arbitrary and not necessarily the same as it was the last time the list was sorted. Is there a way to avoid this?
Here is a code sample:
List<T> myList; // T is arbitrary and I doesn't implement any common interface
PropertyInfo sortPorperty = some property of T
var sortedList = myList.OrderBy(x => sortProperty.GetValue(x));
Multiple executions of this code will result in different order of the objects.
My initial idea is to also sort by the object itself
var sortedList = myList.OrderBy(x => sortProperty.GetValue(x)).ThenBy(x => x);
But as far as I can tell that will sort by hashcode and that is basically the memory location of an object so it would not be the same between runs. Is there anything else that would work?
If the type is serializable then you can use the serialization of the object to serve as the final sort criteria.
Use BinaryFormatter to generate a unique string for the object (which I have called Idem in this example) and use that as the final .ThenBy sorting criteria.
In this example I transformed the binary formatted version of the object to a base64 string (that's performance overhead for sure, and there are other approaches to get the the binary versions to compare nicely, but I'm just illustrating the general approach.)
I think this example has everything you asked for. Arbitrary type with no interface, uses a property as the OrderBy criteria, and does not rely on the initial order of the items to produce the same order of the output on subsequent runs.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
public static class Extensions
{
// Returns a string unique(TM) to this object.
public static string Idem<T>(this T toSerialize)
{
BinaryFormatter formatter = new BinaryFormatter();
var memoryStream = new MemoryStream();
using (memoryStream)
{
formatter.Serialize(memoryStream, toSerialize);
return Convert.ToBase64String(memoryStream.ToArray());
}
}
}
[Serializable()]
public class Person
{
public Person(string name, string secret)
{
this.name = name;
this.secret = secret;
}
private string secret; // some private info
public string Nickname { get { return name; } } // some property
public string name; // some public info
public override string ToString() // a way to see the private info for this demo
{
return string.Format("{0} ({1})", name, secret);
}
}
class Program
{
static void Main(string[] args)
{
// You can rearrange the items in this list and they will always come out in the same order.
List<Person> myList = new List<Person>() {
new Person("Bob", "alpha"),
new Person("Bob", "bravo"),
new Person("Alice", "delta"),
new Person("Bob", "echo"),
new Person("Bob", "golf"),
new Person("Bob", "foxtrot"),
};
PropertyInfo sortProperty = typeof(Person).GetProperty("Nickname");
Random random = new Random();
for (int i = 0; i < 3; ++i)
{
var randomList = myList.OrderBy(x => random.Next());
var sortedList = randomList.OrderBy(x => sortProperty.GetValue(x))
.ThenBy(x => x.Idem()); // Here's the magic "Then By Idem" clause.
Console.WriteLine(string.Join(Environment.NewLine, sortedList));
Console.WriteLine();
}
}
}
I have got a method which returns five arrays of different dimensions:
public static (string[],string[],string[,],string[,],string[,]) deserializeobject(string filename)
{
return (Auftraggeber, Aufstellungsort, Anlagen, Vorgang_rückgemeldet, Vorgang_zukünftig);
}
How do I correctly call this method to further work with the arrays?
I would stronly suggest to create a class for that, in particular as the method is public and thus could be used in multiple contexts. That makes it far easier for users of your API to determine the meaning of every returned member.
Your individual members seem to have a descene tmeaning anyway, so why throw it away and return a collection of namesless paramaters?
class MyObject
{
public string[] Auftraggeber { get; set; }
public string[] Aufstellungsort { get; set; }
public string[] Anlagen { get; set; }
public string[] Vorgang_rückgemeldet { get; set; }
public string[] Vorgang_zukünftig { get; set; }
}
And:
public static MyObject Deserialize(string fileName)
{
return new MyObject { AuftragGeber = ... };
}
Now users of your method can easily determine what the parameters mean:
var o = deserialize(myFile);
DoSomething(o.Aufstellungsort);
which is far easier to read than this:
var o DoSomething(myFile);
DoSomething(o.Item2);
isn´t it? Apart from this it limits typos. In the second case users can easily type Item2 when they actually ment Item1, which may cause headache when debugging. With a descent name for every member those typos are far more unlikely.
First the response to your question:
Given:
public static (string[], string[], string[,], string[,], string[,]) deserializeobject(string filename)
{
// Some value that will be returned... Just doing a test here
return default((string[], string[], string[,], string[,], string[,]));
}
You can:
// Using var
var des1 = deserializeobject("foo.bin");
Console.WriteLine($"Lengths: {des1.Item1.Length}, {des1.Item2.Length}, {des1.Item3.Length}, {des1.Item4.Length}, {des1.Item5.Length}");
// Legal, but too much verbose
(string[], string[], string[,], string[,], string[,]) des2 = deserializeobject("foo.bin");
// Legal too, because in truth the ValueTuple<> struct is used
ValueTuple<string[], string[], string[,], string[,], string[,]> des3 = deserializeobject("foo.bin");
Now, the problem here is that, as I've written in a comment, you need a special type of hate for your coworkers to do this. Why? Because if I ask you, what is Item4, can you give me a response? No :-) Fortunately there are two alternatives: creating a full class/struct to contain the return value or using named tuples. I'm quite against creating a class that will be used only by a single method, so I'll show you the named tuples way.
Using named tuples you can:
public static (string[] Auftraggeber, string[] Aufstellungsort, string[,] Anlagen, string[,] VorgangRückgemeldet, string[,] VorgangZukünftig) deserializeobject2(string filename)
{
return default((string[], string[], string[,], string[,], string[,]));
}
Then you can:
// Using var, with named arguments:
var des4 = deserializeobject2("foo.bin");
Console.WriteLine($"Lengths: {des4.Auftraggeber.Length}, {des4.Aufstellungsort.Length}, {des4.Anlagen.Length}, {des4.VorgangRückgemeldet.Length}, {des4.VorgangZukünftig.Length}");
See? The name of the items (arrays) returned by your method is maintained...
Note that named tuples are a sleight of hand. There are no named tuples underside. There are only ValueTuple<> that are "annotated" with the name of the properties that you want.
This is legal:
ValueTuple<string[], string[], string[,], string[,], string[,]> des5 = des4;
Full example to the question in comment:
public static (string[] Auftraggeber, string[] Aufstellungsort, string[,] Anlagen, string[,] VorgangRückgemeldet, string[,] VorgangZukünftig) deserializeobject2(string filename)
{
// Define/create/fill the arrays
var auftraggeber = new string[10];
var aufstellungsort = new string[10];
var anlagen = new string[10, 10];
var vorgangRückgemeldet = new string[10, 10];
var vorgangZukünftig = new string[10, 10];
// Return the arrays
return (auftraggeber, aufstellungsort, anlagen, vorgangRückgemeldet, vorgangZukünftig);
}
use Tuple<> like below code :
public Tuple<int[], int[]> GetMultipleValue(string name)
{
int[] a = new int[]{1,2,3,4}
int[] b = new int[]{5,6,7,8}
return Tuple.Create(a,b);
}
This application is supposed to be a sort of demo of how blockchain works. I have a block chain class and a block class and the program class is main. In the blockchain class I am creating an initial block called the gensis block in the createGenesisBlock() method. In the constructor of my blockchain class I am calling the createGenesisBlock() method and inserting the object into my linked-list which is called chain. The problem I have is when the object is added to the linked-list in my blockchain class I cannot access the object or the methods. What I am trying to accomplish is to use my getLatestBlock() method in the blockchain class to retrieve the value of hash of the last object that was put into chain. Thus being able to call my addBlock method in blockchain setting the value of previousHash equal to the value of hash of the object in the linked-list
namespace BlockChainProject
{
class Program
{
static void Main(string[] args)
{
Blockchain blockChain = new Blockchain();
blockChain.addBlock();
blockChain.display();
Console.ReadKey();
}
}
}
namespace BlockChainProject
{
class Block
{
private int index;
private string timeStamp;
private string data;
private string previousHash;
private string hash;
public Block(int index, string timeStamp, string data, string previousHash) {
this.index = index;
this.timeStamp = timeStamp;
this.data = data;
this.previousHash = previousHash;
this.hash = this.calculateHash();
}
public string calculateHash() {
SHA256Managed hashString = new SHA256Managed();
byte[] dataArray = hashString.ComputeHash(Encoding.UTF8.GetBytes(index.ToString() + previousHash + timeStamp + data));
StringBuilder stringBuilder = new StringBuilder();
foreach (byte x in dataArray)
{
stringBuilder.AppendFormat("{0:X2}", x);
}
string hashed = stringBuilder.ToString();
return hashed;
}
public string getHash() {
return hash;
}
}
}
namespace BlockChainProject
{
class Blockchain
{
LinkedList<object> chain;
private int index = 0;
private string time = DateTime.Now.ToString();
public Blockchain(){
chain = new LinkedList<object>();
chain.AddLast(createGenesisBlock());
}
private object createGenesisBlock() {
index++;
return new Block(index, time, "Genesis Block", "0"); ;
}
public object getLatestBlock() {
return chain.Last.Value;
}
public void addBlock() {
string data = Console.ReadLine();
//string previousHash = <The hash of linked lists last object here>;
chain.AddLast(new Block(index, time, data, previousHash));
index++;
}
public void display() {
foreach (var item in chain)
{
Console.WriteLine(item);
}
}
}
}
I quickly ran your code and I think that I have figured out your problem. You need to do a find and replace on "object" and replace it with "Block" or alternatively you need to cast the objects that are being returned from the getLast function to "Block".
An example of the changes will look like so:
LinkedList<Block> chain;
...
public Block getLatestBlock() {
return chain.Last.Value;
}
This is some examples of the changes to be made to the Blockchain class there may be others but I can't remember.
Now when you call the display function you have access to the functions and methods of each of the Block class instances in the linked list, like so:
public void display()
{
foreach (var item in chain)
{
Console.WriteLine(item.getHash());
}
}
This will now print a list of the hashes provided that you changed all of the returns, types and instances where you used object in the linked list, to Block.
The reason for this is if you create a linkedlist of generic "object"s then at compile time C# has no idea what might be in the linked lists. It could be Blocks or it could be Bananas, so it doesn't know what functions and methods each object will have available to call. So to let C# know we have to either cast it using "as Block" after we get the item from the list or in your case just set the type of all values in the linked like to "Block" as by the looks of your program you aren't going to have generic entries to the list.
Hopefully this answers your question. If not let me know.
When you specify your chain as
LinkedList<object> chain
You are telling the compiler that the chain variable is a linked list that contains an object class, or any descendent of object.
The following code is therefore legal by your definition of chain
chain.Add("Hi there!");
chain.Add(new Dictionary<int, decimal>());
chain.Add(new Giraffe());
chain.Add(42);
You cannot call calculateHash() because unfortunately, our string, Dictionary, Giraffe and int classes wouldn't know what to do with such a method call.
Instead, chain should be declared as
LinkedList<Block> chain;
This means that chain can only contain elements that are of type Block (or a descendent class of Block).
Whilst the calls to these methods are not shown in code, you will need to then change the createGenesisBlock() and getLatestBlock() methods to return Block rather than object, because you are not allowed to add just any object to your linked list anymore, it must be a Block.
I have the following object
var filters = new List<IReportFilter>
{
new ReportFilter
{
ReportColumn = new ReportColumn{ ColumnKey = "Result.IsCompleted"},
Value = "1",
SubFilters = new List<IReportFilter>
{
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ ColumnKey = "User.LastName"}, Value = "Alhayek"},
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ ColumnKey = "User.LastName"}, Value = "Smith"},
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ AggregateFunction = SqlAggregateFunctions.Count}, Type = FilterType.GreaterThenOrEqualTo ,Value = "0" },
}
},
};
The obove object is passed to another class using a method like so
IReportModel ReportModel = Template.CreateReport();
ReportModel.Get(filters);
Inside the the Get method of the ReportModel class I want to loop through the filters list and create a new list without changing the original list. the new list will become a subset of the original.
From with in my Get method here is what I have done
public SqlCommand Build(List<IReportFilter> filters)
{
var a = CloneFilters(filters);
var b = CloneFilters(filters);
List<IReportFilter> standardFilters = ExtractFiltersByAType(a, true);
List<IReportFilter> aggregateFilter = ExtractFiltersByAType(b, false);
}
But every time I execute the method ExtractFiltersByAType the value of a,b, and filters change to equal the same value of aggregateFilter.
I am NOT expecting for any of the variables to change. But they are for some reason that I don't understand.
Here is my CloneFilters method
private List<IReportFilter> CloneFilters(List<IReportFilter> myFilters)
{
List<IReportFilter> copyOfFilters = new List<IReportFilter>();
foreach (var myFilter in myFilters)
{
copyOfFilters.Add(myFilter);
}
return copyOfFilters;
}
And here is my ExtractFiltersByAType
private List<IReportFilter> ExtractFiltersByAType(List<IReportFilter> filtersSource, bool IsStandard = true)
{
List<IReportFilter> validFilters = new List<IReportFilter>();
foreach (var filterSource in filtersSource)
{
if (filterSource.SubFilters != null && filterSource.SubFilters.Any())
{
filterSource.SubFilters = ExtractFiltersByAType(filterSource.SubFilters, IsStandard); //I think this what could be causing this problem
}
if ((IsStandard && !filterSource.ReportColumn.IsAggregate) || (!IsStandard && filterSource.ReportColumn.IsAggregate))
{
validFilters.Add(filterSource);
}
}
return validFilters;
}
Question
Since I am not using ref to pass the object by reference to the method, why is my function changing the value to original object?
When passing a list of object to method in c#, will the system create a copy or will it passes the object by reference?
How can I solve this problem so that every time I execute ExtractFiltersByAType method, only the copy is changed not the originals?
I am thinking that the line filterSource.SubFilters = ExtractFiltersByAType(filterSource.SubFilters, IsStandard); in the ExtractFiltersByAType is causing the problem but I don't understand why and how.
Without ref
When you pass a reference type as an argument (which includes a list), you pass a copy of the reference to that object. This means you can change your object attributes, but can't change the object itself.
Example:
public class Program
{
static void Main(string[] args)
{
Foo foo = new Foo(1);
Console.WriteLine(foo.Bar);
// This will change foo.Bar
ChangeFoo(foo, 5);
Console.WriteLine(foo.Bar);
// Does not change foo
DoesNotChangeFoo(foo, 10);
Console.WriteLine(foo.Bar);
Console.Read();
}
static void ChangeFoo(Foo foo, int newValue)
{
// Since it receives a copy of the reference to Foo, it actually changes foo.Bar value
foo.Bar = newValue;
}
static void DoesNotChangeFoo(Foo foo, int newValue)
{
// Since it receives a copy of the reference to foo, it only updates this method's reference, not changing the caller's reference
foo = new Foo(newValue);
}
}
public class Foo
{
public Foo(int bar)
{
Bar = bar;
}
public int Bar { get; set; }
}
With ref
If you wanted to change the caller's object reference, you would need to pass the actual reference used by the calle's, that's when you use the ref keyword.
Example:
public class Program
{
static void Main(string[] args)
{
Foo foo = new Foo(1);
Console.WriteLine(foo.Bar);
// This will change foo's object reference
ChangeFooObjectReference(ref foo, 15);
Console.WriteLine(foo.Bar);
Console.Read();
}
static void ChangeFooObjectReference(ref Foo foo, int newValue)
{
// SInce you are receiving the actual reference used by the caller, you actually change it's own reference
foo = new Foo(newValue);
}
}
public class Foo
{
public Foo(int bar)
{
Bar = bar;
}
public int Bar { get; set; }
}
Your case
As you correcly assumed, the main cause of your problem is this line:
filterSource.SubFilters = ExtractFiltersByAType(filterSource.SubFilters, IsStandard);
This line actually changes this object's SubFilters.
But it's worth noting that you may have some bigger problems in you Clone method.
private List<IReportFilter> CloneFilters(List<IReportFilter> myFilters)
{
List<IReportFilter> copyOfFilters = new List<IReportFilter>();
foreach (var myFilter in myFilters)
{
copyOfFilters.Add(myFilter);
}
return copyOfFilters;
}
This method return's a new List, but the content of that list is exactly the same as the argument's. This means that, if you change any of the object's contained in the object used as an argument, you change it in the new List too.
Here's an example of what's happening.
static void Main(string[] args)
{
List<Foo> foos = new List<Foo>();
foos.Add(new Foo(2));
List<Foo> newFoo = CreateNewFoo(foos);
Console.WriteLine(newFoo.First().Bar);
foos.First().Bar = 5;
// Since we changed the first object of the old list, and it is the same object in the new list, we will get the new result.
Console.WriteLine(newFoo.First().Bar);
Console.Read();
}
static List<Foo> CreateNewFoo(List<Foo> foos)
{
List<Foo> newFoos = new List<Foo>();
foreach(Foo foo in foos)
{
newFoos.Add(foo);
}
return newFoos;
}
I would suggest implementing the ICloneable interface in your IReportFilter interface, and each concrete class implementing IReportFilter.
ICloneable implements a single method Clone(), which returns an object. This method should create a new instance of the same class in which it's implemented, containing a new object identical to the current object. Than you would change your method to:
private List<IReportFilter> CloneFilters(List<IReportFilter> myFilters)
{
List<IReportFilter> copyOfFilters = new List<IReportFilter>();
foreach (var myFilter in myFilters)
{
copyOfFilters.Add(myFilter.Clone() as IReportFilter);
}
return copyOfFilters;
}
As for implementing the ICloneable inteface, refer to this question:
Proper way to implement ICloneable
Edit
As mentioned by user muratgu in the question comments, your CloneFilter method is doing a shallow copy of your list, what you are looking for is a deep copy. That could be implemented with the aforementioned ICloneable interface.
The only thing that ref does is determine whether the method receiving the parameter can modify the variable passed to it. In the case of an object, that means setting the variable to a different object or setting it to null.
But even if you don't use ref, the method you pass the parameter to can can set its properties or call methods which modify the state of that object. That's normal and expected. When you pass an object to another method, it's not just so that the other method can read its properties. You might also want that method to operate on that object in some way that modifies it.
The simplest example is a List<T>. If you pass a List<string> to another method - without using ref - that other method can add items to the list, modify items in the list, clear the list, etc.
The only difference with using ref is that if the method you pass the variable to sets the variable to a different list or sets it to null, it's going to modify the variable in the method that passed the argument.
Most of the time we don't want a method we call to completely replace the variable we pass in. If we wanted a new object we'd write a function that returns an object, not one that replaces the variable we passed in.
Related: How do I create a static local variable in Java?
Pardon if this is a duplicate; I was pretty sure this would have been asked previously, and I looked but didn't find a dupe.
Is it possible for me to create a static local variable in C#? If so, how?
I have a static private method that is used rarely. the static method uses a Regular Expression, which I would like to initialize once, and only when necessary.
In C, I could do this with a local static variable. Can I do this in C#?
When I try to compile this code:
private static string AppendCopyToFileName(string f)
{
static System.Text.RegularExpressions.Regex re =
new System.Text.RegularExpressions.Regex("\\(copy (\\d+)\\)$");
}
...it gives me an error:
error CS0106: The modifier 'static' is not valid for this item
If there's no local static variable, I suppose I could approximate what I want by creating a tiny new private static class, and inserting both the method and the variable (field) into the class. Like this:
public class MyClass
{
...
private static class Helper
{
private static readonly System.Text.RegularExpressions.Regex re =
new System.Text.RegularExpressions.Regex("\\(copy (\\d+)\\)$");
internal static string AppendCopyToFileName(string f)
{
// use re here...
}
}
// example of using the helper
private static void Foo()
{
if (File.Exists(name))
{
// helper gets JIT'd first time through this code
string newName = Helper.AppendCopyToFileName(name);
}
}
...
}
Thinking about this more, using a helper class like this there would yield a bigger net savings in efficiency, because the Helper class would not be JIT'd or loaded unless necessary. Right?
No, C# does not support this. You can come close with:
private static System.Text.RegularExpressions.Regex re =
new System.Text.RegularExpressions.Regex("\\(copy (\\d+)\\)$");
private static string AppendCopyToFileName(string f)
{
}
The only difference here is the visibility of 're'. It is exposed to the classm not just to the method.
The re variable will be initialized the first time the containing class is used in some way. So keep this in a specialized small class.
Not in C#, only in Visual Basic .NET:
Sub DoSomething()
Static obj As Object
If obj Is Nothing Then obj = New Object
Console.WriteLine(obj.ToString())
End Sub
VB.NET have lot of nice things that C# does not have, thats why I choose VB.NET.
Unfortunately, no. I really loved this possibility in C.
I have an idea what you could do.
Create a class that will provide access to instance-specific values, which will be preserved statically.
Something like this:
class MyStaticInt
{
// Static storage
private static Dictionary <string, int> staticData =
new Dictionary <string, int> ();
private string InstanceId
{
get
{
StackTrace st = new StackTrace ();
StackFrame sf = st.GetFrame (2);
MethodBase mb = sf.GetMethod ();
return mb.DeclaringType.ToString () + "." + mb.Name;
}
}
public int StaticValue
{
get { return staticData[InstanceId]; }
set { staticData[InstanceId] = value; }
}
public MyStaticInt (int initializationValue)
{
if (!staticData.ContainsKey (InstanceId))
staticData.Add (InstanceId, initializationValue);
}
}
Can be used this way...
class Program
{
static void Main (string[] args)
{
// Only one static variable is possible per Namespace.Class.Method scope
MyStaticInt localStaticInt = new MyStaticInt (0);
// Working with it
localStaticInt.StaticValue = 5;
int test = localStaticInt.StaticValue;
}
}
It's not a perfect solution, but an interesting toy.
You can only have one static variable of this type per Namespace.Class.Method scope. Won't work in property methods - they all resolve to the same name - get_InstanceId.
C# doesn't support static local variables. In addition to what has been posted above, here's a 2004 MSDN blog entry on the subject: Why doesn't C# support static method variables?
(Same blog entry in the Microsoft's own archive. The Web Archive preserved the comments. Microsoft archive didn't.)
Why not create a static readonly member on your class and initialize it in a static constructor maybe?
This will give you the same performance benefit - it will only get initialised once.
What about this, since you only want it to be initialized if it's used:
private static System.Text.RegularExpressions.Regex myReg = null;
public static void myMethod()
{
if (myReg == null)
myReg = new Regex("\\(copy (\\d+)\\)$");
}
I developed a static class that deals with this problem in a fairly simple manner:
using System.Collections.Generic;
using System.Runtime.CompilerServices;
public static class StaticLocal<T>
{
static StaticLocal()
{
dictionary = new Dictionary<int, Dictionary<string, Access>>();
}
public class Access
{
public T Value { get; set; }
public Access(T value)
{
Value = value;
}
}
public static Access Init(T value, [CallerFilePath]string callingFile = "",
[CallerMemberName]string callingMethod = "",
[CallerLineNumber]int lineNumber = -1)
{
var secondKey = callingFile + '.' + callingMethod;
if (!dictionary.ContainsKey(lineNumber))
dictionary.Add(lineNumber, new Dictionary<string, Access>());
if (!dictionary[lineNumber].ContainsKey(secondKey))
dictionary[lineNumber].Add(secondKey, new Access(value));
return dictionary[lineNumber][secondKey];
}
private static Dictionary<int, Dictionary<string, Access>> dictionary;
}
It can be implemented within a method like this:
var myVar = StaticLocal<int>.Init(1);
Console.Writeline(++myVar.Value);
On each subsequent call to the method, the value contained in myVar.Value will be the last one it was set to so repeated calls will cause it to output a sequence of natural numbers. The Init() function only sets the value if it has not been previously initialized. Otherwise it just returns a reference to an object containing the value.
It makes use of the [CallerFilePath], [CallerMemberName] and [CallerLineNumber] attributes to track which item in the dictionary is being referred to. This eliminates the possibility of collisions between methods with the same names or calls from the same line numbers.
A few caveats about its usage:
As others have stated, it's worthwhile to consider whether what you're doing really requires the use of static local variables. Their use can sometimes be a sign that your design is flawed and could use some refactoring.
This method of dealing with the problem involves a couple layers of indirection, slowing down the execution of your program. It should only be used if it justifies that cost.
Static local variables can help you to deal with having too many members declared in your class, thus compartmentalizing them where they're used. This should be weighed against the execution time cost but can sometimes be worth it. On the other hand, having so many members being declared within a class may be an indication of design problems worth considering.
Because these values continue to remain in memory after their methods complete execution you must be mindful that using them to store large chunks of memory will prevent garbage-collection until the program completes, thus diminishing your available resources.
This approach is probably overkill for most instances where you would want to use static local variables. Its use of indirection to deal with separate files, methods and lines might be unnecessary for your project, in which case you can simplify it to meet your needs.
Sure. You just have to declare the private static variable outside of the method.
private static readonly System.Text.RegularExpressions.Regex re = new System.Text.RegularExpressions.Regex( "\\(copy (\\d+)\\)$" );
private static string AppendCopyToFileName( string f )
{
//do stuff.
}
This is effectively what you are doing with the only difference being that "re" has visibility to the entire class as opposed to just the method.
I haven't seen a good generic solution to this yet so I thought I'd come up with my own. I should note however that for the most part(not always) needing static local variables is probably a sign that you should refactor your code for the reasons that have been stated by many people; state is something for the object not a method. I do however like the idea of limiting the scope of variables.
Without further ado:
public class StaticLocalVariable<T>
{
private static Dictionary<int, T> s_GlobalStates = new Dictionary<int, T>();
private int m_StateKey;
public StaticLocalVariable()
{
Initialize(default(T));
}
public StaticLocalVariable( T value )
{
Initialize(value);
}
private void Initialize( T value )
{
m_StateKey = new StackTrace(false).GetFrame(2).GetNativeOffset();
if (!s_GlobalStates.ContainsKey(m_StateKey))
{
s_GlobalStates.Add(m_StateKey, value);
}
}
public T Value
{
set { s_GlobalStates[m_StateKey] = value; }
get { return s_GlobalStates[m_StateKey]; }
}
}
This isn't thread safe of course but it wouldn't take too much work to make it so. It can be used like so:
static void Main( string[] args )
{
Console.WriteLine("First Call:");
Test();
Console.WriteLine("");
Console.WriteLine("Second Call:");
Test();
Console.ReadLine();
}
public static void Test()
{
StaticLocalVariable<int> intTest1 = new StaticLocalVariable<int>(0);
StaticLocalVariable<int> intTest2 = new StaticLocalVariable<int>(1);
StaticLocalVariable<double> doubleTest1 = new StaticLocalVariable<double>(2.1);
StaticLocalVariable<double> doubleTest2 = new StaticLocalVariable<double>();
Console.WriteLine("Values upon entering Method: ");
Console.WriteLine(" intTest1 Value: " + intTest1.Value);
Console.WriteLine(" intTest2 Value: " + intTest2.Value);
Console.WriteLine(" doubleTest1 Value: " + doubleTest1.Value);
Console.WriteLine(" doubleTest2 Value: " + doubleTest2.Value);
++intTest1.Value;
intTest2.Value *= 3;
doubleTest1.Value += 3.14;
doubleTest2.Value += 4.5;
Console.WriteLine("After messing with values: ");
Console.WriteLine(" intTest1 Value: " + intTest1.Value);
Console.WriteLine(" intTest1 Value: " + intTest2.Value);
Console.WriteLine(" doubleTest1 Value: " + doubleTest1.Value);
Console.WriteLine(" doubleTest2 Value: " + doubleTest2.Value);
}
// Output:
// First Call:
// Values upon entering Method:
// intTest1 Value: 0
// intTest2 Value: 1
// doubleTest1 Value: 2.1
// doubleTest2 Value: 0
// After messing with values:
// intTest1 Value: 1
// intTest1 Value: 3
// doubleTest1 Value: 5.24
// doubleTest2 Value: 4.5
// Second Call:
// Values upon entering Method:
// intTest1 Value: 1
// intTest2 Value: 3
// doubleTest1 Value: 5.24
// doubleTest2 Value: 4.5
// After messing with values:
// intTest1 Value: 2
// intTest1 Value: 9
// doubleTest1 Value: 8.38
// doubleTest2 Value: 9
Along the lines of Henk's and BarretJ's answer, I think you can avoid the initialization cost and come even closer by using a property,
private Regex myReg = null;
private Regex MyReg
{
get {
if (myReg == null)
myReg = new Regex("\\(copy (\\d+)\\)$");
return myReg;
}
}
Then just use MyReg (note the uppercase 'M' in MyReg) everywhere in your code. The nice thing about this solution is that (although the getter is a function call under the hood) the semantics of properties means that you get to write code as if MyReg was a variable.
The above is how I setup "runtime constants" that require a one-time initialization at runtime.
I do the same thing using nullable types, too. For example,
private bool? _BoolVar = null;
private bool BoolVar
{
get {
if (_BoolVar.HasValue)
return (bool)_BoolVar;
_BoolVar = /* your initialization code goes here */;
return (bool)_BoolVar;
}
}
Then just use BoolVar like a regular normal bool in your code. I don't use internal _BoolVar (the backing store for the BoolVar property) because I just don't need to, remember this is like a runtime constant, so there is no setter. However, if I needed to change the value of the runtime constant for some reason, I'd do that directly on the nullable variable _BoolVar.
The initialization could be pretty involved. But it's only executed one time and only on the first access of the property. And you have the choice of forcing the re-initialization of the runtime constant value by setting _BoolVar back to null.
Nesting the related members in an inner class as you have shown in question is the cleanest most probably. You need not push your parent method into inner class if the static variable can somehow get the caller info.
public class MyClass
{
...
class Helper
{
static Regex re = new Regex("\\(copy (\\d+)\\)$");
string caller;
internal Helper([CallerMemberName] string caller = null)
{
this.caller = caller;
}
internal Regex Re
{
//can avoid hard coding
get
{
return caller == "AppendCopyToFileName" ? re : null;
}
set
{
if (caller == "AppendCopyToFileName")
re = value;
}
}
}
private static string AppendCopyToFileName(string f)
{
var re = new Helper().Re; //get
new Helper().Re = ...; //set
}
private static void Foo()
{
var re = new Helper().Re; //gets null
new Helper().Re = ...; //set makes no difference
}
}
You can avoid hard coding of method names in the property using some expression tree tricks.
You can avoid the helper constructor and make the property static, but you need to get the caller info inside the property, via using StackTrace.
Lastly, there is always const possible inside a method, but then one, it's not variable, two, only compile time constants are allowed. Just stating.
Three years later...
You can approximate it with a captured local variable.
class MyNose
{
private static void Main()
{
var myNose= new MyNose();
var nosePicker = myNose.CreatePicker();
var x = nosePicker();
var y = nosePicker();
var z = nosePicker();
}
public Func<int> CreatePicker()
{
int boog = 0;
return () => boog++;
}
}
I was reading this post recently, because I was courious to know, if the mentioned Visual Basic feature (or C feature, which I wasn't aware) would exist in C# as well.
However, I took some time to put together a solution of all the pre-posts. Some word in advance:
It's not thread safe (but you can bulid it that way)
Because of the use of StackFrame it's painfully slow (as statet in previous post)
The solution approach includes not just static local variables, but also non-static variables with proper memory clean-up
It's bricolage
The tool is this class:
public static class Persistent<T> where T : struct
{
static readonly Dictionary<int, T[]> staticValues;
public static ref T Static(T value)
{
var stackFrameOffset = new StackFrame(1, false).GetNativeOffset();
if (!staticValues.ContainsKey(stackFrameOffset))
staticValues.Add(stackFrameOffset, new T[] { value });
return ref staticValues[stackFrameOffset][0];
}
static readonly ConditionalWeakTable<object, Dictionary<int, T[]>>
nonStaticValues;
public static ref T Local(T value, object callerInstance)
{
var stackFrameOffset = new StackFrame(1, false).GetNativeOffset();
if (!nonStaticValues.TryGetValue(callerInstance, out var storage))
{
storage = new Dictionary<int, T[]>
{
{ stackFrameOffset, new T[] {value} }
};
nonStaticValues.Add(callerInstance, storage);
}
else if (!storage.ContainsKey(stackFrameOffset))
{
storage.Add(stackFrameOffset, new T[] { value });
}
return ref storage[stackFrameOffset][0];
}
static Persistent()
{
staticValues = new Dictionary<int, T[]>();
nonStaticValues = new ConditionalWeakTable<object,
Dictionary<int, T[]>>();
}
}
And the use is like that:
public void Method1()
{
ref int myInt = ref Persistent<int>.Local(0, this);
myInt++;
Console.WriteLine($"myInt is now {myInt}");
}
The same applies for Persistent.Static(77) instead of Local where one is for static values while the other method is vor non-static ones...
If you like to read my considerations about, look here:
https://csatluegisdorf.blogspot.com/2021/11/persistent-variables-for-method-scope.html
Here is sort of a hackish way to accomplish what you're trying to do. Turn MyMethod into an Action that creates a closure on x. The variable x will only be visible to the innermost delegate, and behaves like a static variable. If anyone has any suggestions for improving this pattern let me know.
public static readonly Func<string, string> MyMethod = new Func<Func<string, string>>(delegate ()
{
var x = new Regex("abc", RegexOptions.IgnoreCase); //this Regex will be "static"
return delegate (string input) { return x.Replace(input, "123"); };
}).Invoke();
//example usage:
public void Init()
{
Console.WriteLine(MyMethod("abc")); //console will output "123"
}