I want to create an array of Disc which id like to include fields string[] Record, int NumberHeads and string extension. so basically grouping them and instantiate the array once and only once as i dont want more than one of this array in the memory. How can i do this as my fields dont seem to be under the array Disc and if i make them public and run the application i get a null reference exception.
I was initially using a struct but I came to realise these cannot be passed from class to class in C#.
class DiscType
{
private static DiscType[] disc;
private static string[];
public bool discSelect;
public int maxRecord;
public int numberHeads;
public string extension;
public static string[] Record
{
get
{
if (record == null)
{
record = new string[1000];
}
return record;
}
}
public static DiscType[] Disc
{
get
{
if (disc == null)
{
disc = new DiscType[10];
}
return disc;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < DiscType.Disc.Length; i++)
{
DiscType.Disc[i].Record[i]= "1";
}
}
}
If you want only once instanciation of your array do it like that :
public class Singleton
{
private static Singleton instance;
public string[] MyArray { get; set; }
//better using a List<string>
private Singleton() {
//instanciate MyArray here
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
After that you just need to call it like that :
Singleton.intance.MyArray
You describe two problems:
After you think you created a DiscType and an array of records, your array of records only contains null values
Your DiscType is not a singleton.
Is Disctype a singleton?
Someone else already described how to create a Singleton, So I wont write this. However I doubt whether DiscType in your design really is a singleton. If you'd describe your design in words, would you talk about the one and only disctype, or would you say: "Although in my designed world it could be that there were several different disctypes, however because of the huge amount of memory and mabye because of the time it takes to create one, it is advised to use only one disctype during the session".
In the latter case, you should not design it as a singleton. The famous gang of four wrote in their book about design patterns (where the singleton is described) as one of the major rules of design:
Design for change
That means, that you should not restrict your design merely for the case that in the current usage it is not needed. If in your current configuration you only need one disctype, just create only one. If in future versions you need two, you don't need to change your disctype.
So careful review your design: are we talking about "the one and only disctype"? or are we only restricting to one because we don't have enough memory?
Why is my array of records empty
To understand this, you need to know the difference between value types and reference types. Simple types and structs are value types. They exist as soon as you declare them. Instances of classes are always reference types: you need to call new ... to create them. If you don't do this, the value is null.
Myclass X;
string text;
int i;
System.Drawing.Point p; // a Point is a struct!
X and text both have a null value, the only thing you can do with them before you assign something to them is compare them with null
i and p already have a value. You can get them and call their methods.
Back to your problem
Your code:
public static string[] Record
{
get
{
if (record == null)
{
record = new string[1000];
}
return record;
}
}
You assign a newly created object to record. the object is an array of strings, which are reference types. You haven't assigned anything to each string, so each string in your array is still null, and you can't do anything with them until you assign something.
The array of strings however is initialized. You can use methods of the array. You can ask for the length of the array. You can also ask for item[3] in which you get the uninitialized (null) string.
List instead of Array
By the way, this method of initializing is a bit unusual. I guess you don't want to reserve memory for records as long as you don't use them. You would have accomplished that by using List.
My advise is to familiarize yourself with class List. It will make your life so much easier. Before long you'll feel the desire to know all collection classes :-)
Related
I am trying to link 2 different classes together. Relationship is a one to many relationship. So I'm trying to make a program which will let me make every object unique. So I decided to add Unique IDs to each object. How can I make a method that will give me a unique number that won't be repeated.
I'm using C# .net5.0.
EDIT: a method that just gives a number that hasn't been used before is ok too. For example, 1, and then it will check if 1 has been used before if not than it will use one and if yes than it will use 2
You could use a static counter, something like this:
class Thing {
static int IdCount;
private int id;
public Thing() {
IdCount++;
this.id = IdCount;
}
...
}
The counter will be zero initially (the default integer value) and will increment on each instantiation of the class and assign the new value to the ID field of the object.
Be aware that this is not thread-safe and may not be appropriate for your needs.
EDIT (following question edit and comment):
You could use a function to generate the ID number but you should still consider thread-safety. A simple lock might be enough for your needs, something like this:
class Thing {
static int IdCount;
static readonly object objectLock = new object();
private int id;
public Thing() {
this.id = GetIdNumber();
}
private static GetIdNumber() {
lock (objectLock) {
IdCount++;
return IdCount;
}
}
}
The lock will prevent a second, near-simultaneous instantiation from incrementing the counter before the first instantiation has had chance to return the number. For anything more complex you could look at (e.g.) the Interlocked class.
It should be obvious that the above are runtime-only solutions; values will not persist outside the lifetime of the application.
I have some delegates, two classes and a struct that look kind of like this:
delegate Value Combination(Value A, Value B);
class Environment
{
private Combination[][] combinations;
private string[] typenames;
private getString[] tostrings;
public Environment() { ... } //adds one 'Null' type at index 0 by default
public void AddType(string name, getString tostring, Combination[] combos) { ... }
public Value Combine(Value A, Value B)
{
return combinations[A.index][B.index](A, B);
}
public string getStringValue(Value A)
{
return tostrings[A.index](A);
}
public string getTypeString(Value A)
{
return typenames[A.index];
}
}
class Container
{
public string contents
{
get
{
return data.text;
}
}
public string contentType
{
get
{
return data.type;
}
}
private Value data;
public Container(Value val)
{
data = val;
}
public Container CombineContents(Container B)
{
return new Container(data.Combine(B.data))
}
}
struct Value
{
public string type
{
get
{
return environment.getTypeString(this);
}
}
public string text
{
get
{
return environment.getStringValue(this);
}
}
public readonly int type;
public readonly byte[] raw;
public readonly Environment environment;
public Value(int t, byte[] bin, Environment env)
{
type = t;
raw = bin;
environment = env;
}
public Value Combine(Value B)
{
return environment.Combine(this, B)
}
}
The reason for this structure is that Containers can have Values of various types, which combine with each other in user-defined ways according to the current Environment (which, like Container and Value, is differently named so as to avoid conflicting with the System.Environment class in my actual code- I used the name here to concisely imply its function). I cannot get around the problem with subclasses of Value and generic Containers since values of different types still need to be combinable, and neither Container nor the base Value class can know what type of Value combination should return.
It doesn't seem possible to define the Environment class in a global way, as the existing System.Environment class doesn't seem to allow storing delegates as user variables, and giving it a static method returning an instance of itself would render it unmodifiable*, and would require a new instance of the class to be created every time I want to do anything with Values, which seems like it should be a huge performance hit.
This causes two problems for me:
There is an extra reference padding out all my Values. Values are variable in size, but raw is almost always 8 bits or less, so the difference is significant, especially since in actual implementations it will be fairly common to have several million Values and Containers in memory at once.
It is impossible to define a proper 'null' Value, as a Value must have an Environment in it and the Environment must be mutable. This in turn means that Container constructors that do not take a Value as an argument are much more convoluted.
The only other way around this I can think of would be to have a wrapper class (either an extension of Environment or something with an environment as a parameter) which is required in order to work with Containers or Values, which has all extant Containers and Values as members. This would solve the 'null' problem and neaten up the Value class a bit, but adds a huge amount of overhead as described and makes for a really convoluted interface for the end user. Those problems are, with a good deal of work and some changes in program flow, solvable as well, but by that point I'm pretty much writing another programming language which is far more than I should need.
Is there any other workaround for this that I'm missing, or am I mistaken about any of my disqualifying factors above? The only thing I can think of is that the performance hit from the static implementation might be smaller than I think it would be due to cacheing (I cannot perform realistic benchmarking unfortunately- there are too many variables in how this could be used).
*Note that an environment doesn't strictly speaking need to be modifiable- there would be no problem, technically, for example, with something like
class Environment
{
private Combination[][] combinations;
private string[] typenames;
private getString[] tostrings;
public Environment(Combination[][] combos, string[] tnames, getString[] getstrings)
{
combinations = combos;
typenames = tnames;
tostrings = getstrings;
}
}
except that this would be much more awkward for the end user, and doesn't actually fix any of the problems I've noted above.
I had a lot of trouble trying to understand exactly what you were trying to achieve here! So apologies if I'm off the mark. Here is a singleton based example that, if I understand the problem correctly, may help you:
public class CombinationDefinition
{
public string Name;
public getString GetString;
public Combination[] Combinations;
}
public static class CurrentEnvironment
{
public static CombinationDefinition[] Combinations = new CombinationDefinition[0];
public static Environment Instance { get { return _instance.Value; } }
static ThreadLocal<Environment> _instance = new ThreadLocal<Environment>(() =>
{
Environment environment = new Environment();
foreach (var combination in Combinations)
environment.AddType(combination.Name, combination.GetString, combination.Combinations);
return environment;
});
public static Value CreateValue(int t, byte[] bin)
{
return new Value(t, bin, Instance);
}
}
Which can be used as:
CurrentEnvironment.Combinations = new CombinationDefinition[]
{
new CombinationDefinition() { Name = "Combination1", GetString = null, Combinations = null },
new CombinationDefinition() { Name = "Combination2", GetString = null, Combinations = null },
};
Value value = CurrentEnvironment.CreateValue(123, null);
string stringValue = CurrentEnvironment.Instance.getStringValue(value);
Important to note - CurrentEnvironment.Combinations must be set before the Environment is used for the first time as accessing the Instance property for the first time will cause the Environment to be instantiated by its ThreadLocal container. This instantiation uses the values in Combinationsto use the existing AddType method to populate the Environment.
You either need to make Environment a "Singleton" (recomended), or mark everything inside it as static. Another possibility is to use an IoC container, but that may be more advanced than you are ready to go for at this point.
The Singleton pattern usually declared a static Instance property that is initialized to a new instance of the class through a private constructor. All access is done through the static Instance property, which will be available globally. You can read more about Singletons in C# here.
static will allow you to access the members without instantiating an instance of the class and it will act as a "global" container.
Singleton Example:
class Environment
{
private static Environment _instance;
public static Environment Instance
{
get
{
if (_instance == null)
{
_instance = new Environment();
}
return _instance;
}
}
private Environment(){}
private Combination[][] combinations;
private string[] typenames;
private getString[] tostrings;
public Environment() { ... } //adds one 'Null' type at index 0 by default
public void AddType(string name, getString tostring, Combination[] combos) { ... }
public Value Combine(Value A, Value B)
{
return combinations[A.index][B.index](A, B);
}
public string getStringValue(Value A)
{
return tostrings[A.index](A);
}
public string getTypeString(Value A)
{
return typenames[A.index];
}
}
Example usage:
Environment.Instance.getStringValue(this);
Please excuse any syntax errors in code, I don't have access to Visual Studio at the moment.
Say I have a class with a number of methods - some private, some public.
In one of the public methods, I create a list of objects. This is then used across a number of other methods, which have simply been abstracted out to make code simpler.
So I might have:
public class MyClass
{
public void CreateList()
{
List<MyClass> MyList = new List<MyClass>();
... populate list
DedupeList();
ValidateList();
}
void DedupeList()
{
// do something using MyList
}
void ValidateList()
{
// do something using MyList
}
}
I was wondering what the best approach would be in this instance.
Make the list created by CreateList() a class level variable;
Pass the list a parameter to each of the sub-methods.
Ok, so it depends on what you're trying to achieve and what your classes responsibility is.
If you class represents a real thing which represents part of your domain, and which has state, then your private methods act on that state and I would therefore choose the former.
So
public class Basket
{
private IList<string> Contents;
public Basket()
{
Contents = new Contents();
}
public void Add(string Item)
{
Contents.Add(Item);
}
public void Empty()
{
Contents.Clear();
}
}
This is a trite example, but all I could think of.
If however your class doesn't represent an object with state, such as the calculator below which takes some input, acts on it, and returns it without storing anything, then the latter is better.
That said, there are other considerations, such as keeping code clean and easy to read (should be very high on your priority list), limiting the number of parameters etc being passed (any more than three is often regarded as messy). Example below of when I would elect to pass parameters.
public class InvestmentCalculator
{
pubilc IEnumerable<Stock> CalculateInvestmentValue(IEnumerable<Stock> Stocks)
{
foreach (var stock in stocks)
{
var itemValue = GetSotckValueFromMarket(stock);
stock.UpdateValue(itemValue)
AddProjection(stock);
}
}
public decimal GetStockValueFromMarket(Stock stock)
{
//Do something
}
public decimal AddProjection(Stock stock)
{
//Do something
}
}
I hope that this helps
It depends on meaning of the list. You have to find some answers. Should it be a part of the class or just a temporary variable that should live just along the method call? Is it a part of behavior of the class? How about threading? Even you may rethink if DedupeList and ValidateList methods have to be part of this class or do they deserve a separate class?
I recommend you to read "Implementation Patterns" by Kent Beck and "Clean Code" by Robert C. Martin. There are dozens of very helpful tips for these kind of little but frequent cases.
I have just recently got involved in a classic ASP.NET project which contains lots of storing and reading values from the session and query strings. This could look something like the following:
Session["someKey"]=someValue;
And somewhere else in the code the value in the session is read. Clearly this violates the DRY principle since you'll have the literal string key spread out all over the code. One way to avoid this could be to store all keys as constants that could be referenced everywhere there is a need to read and write to the session. But I'm not sure that's the best way to do it. How would you recommend I best handle this so that I don't violate the DRY principle?
Create a separate public class where you can define your constants, e.g
public class SessionVars
{
public const string SOME_KEY = "someKey";
public const string SOME_OTHER_KEY = "someOtherKey";
}
and then anywhere in your code you can access session variables like this:
Session[SessionVars.SOME_KEY]=someValue;
This way you can get IntelliSence and other bells and whistles.
I think you're reading too much into DRY. I pertains more to things that could be wrapped up in a function. I.e. instead of repeating the same fives lines all over the place wrap those 5 lines in a function and call the function everywhere you need it.
What you have as an example is just setting a value in a dictionary (the session object in this case), and that is the simplest way to store and retrieve objects in it.
I can't remember for the life of me where I humbly re-purposed this code from, but it's pretty nice:
using System;
using System.Web;
namespace Project.Web.UI.Domain
{
public abstract class SessionBase<T> where T : class, new()
{
private static readonly Object _padlock = new Object();
private static string Key
{
get { return typeof(SessionBase<T>).FullName; }
}
public static T Current
{
get
{
var instance = HttpContext.Current.Session[Key] as T;
lock (SessionBase<T>._padlock)
{
if (instance == null)
{
HttpContext.Current.Session[Key]
= instance
= new T();
}
}
return instance;
}
}
public static void Clear()
{
var instance = HttpContext.Current.Session[Key] as T;
if (instance != null)
{
lock (SessionBase<T>._padlock)
{
HttpContext.Current.Session[Key] = null;
}
}
}
}
}
The idea behind it two fold. The type created should be the only type you need. It's basically a big strongly-typed wrapper. So you have some object you want to keep extending information in:
public class MyClass
{
public MyClass()
public string Blah1 { get; set; }
}
Then down the road you extend MyClass and you don't want to have to remember all the Key Values, store them in AppSettings or Const variables in Static Classes. You simply define what you want to store:
public class MyClassSession : SessionBase<MyClass>
{
}
And anywhere in your program you simply use the class.
// Any Asp.Net method (webforms or mvc)
public void SetValueMethod()
{
MyClassSesssion.Current.Blah1 = "asdf";
}
public string GetValueMethod()
{
return MyClassSession.Current.Blah1;
}
Optionally you could place the access to this session object in a base page and wrap it in a property:
class BasePage : Page
{
...
public string MySessionObject
{
get
{
if(Session["myKey"] == null)
return string.Empty;
return Session["myKey"].ToString();
}
set
{
Session["myKey"] = value;
}
}
...
}
Here you are repeating the myKey string but it is encapsulated into the property. If you want to go to the extreme of avoiding this, create a constant with the key and replace the string.
I'm trying to recreate the generic List collection. This is my code to Add items to the collection and Show all of them:
public class Collect<TItem>
{
public Collect<TItem> collectObject;
public TItem firstObject;
public void Add(TItem item)
{
if (collectObject == null)
{
collectObject = new Collect<TItem>();
collectObject.firstObject = item;
}
else
{
this.collectObject.Add(item);
}
}
public void Show()
{
if (firstObject != null)
Console.WriteLine(firstObject.ToString());
if (collectObject != null)
collectObject.Show();
}
You'd use this class like this:
Collect<int> test = new Collect<int>();
test.Add(2);
test.Add(10);
test.Add(30);
test.Add(3);
test.Show();
It prints all of the values above, but the first item is always 0.
0
2
10
30
3
This is because the very first firstObject variable is never assigned and gets the default value, but I can't figure out a way to get this fixed. The book I learned this assigns the first firstObject variable in a constructor that expects a TItem object, but I want to do it without using a constructor for this collection (to recreate a List)
I know this is exactly the same like how a generic List works, but I just want to understand the logic behind it. Thanks for the help.
You can make your TItem nullable, which allows your test to work. Also, you need to set the firstObject in the top instance of Collect, not the referenced one.
public class Collect<TItem> where TItem : struct
{
public Collect<TItem> collectObject;
public TItem? firstObject;
public void Add(TItem item)
{
if (collectObject == null)
{
collectObject = new Collect<TItem>();
firstObject = item;
}
else
{
this.collectObject.Add(item);
}
}
public void Show()
{
if (firstObject.HasValue)
Console.WriteLine(firstObject.ToString());
if (collectObject != null)
collectObject.Show();
}
}
OK, this is doing my head in, but I think you want to do something like:
if (collectObject == null)
{
collectObject = new Collect<TItem>();
this.firstObject = item;
}
because otherwise you are never actually assigning anythign tothe firstobject property of the object you are creating.
What you doing wrong is collectObject.firstObject = item; should be this.firstObject = item;
I think you just have to change the line:
collectObject.firstObject = item;
to
firstObject = item;
This way your custom collection will always be represented by a "head" and a "tail" - I assume this is what you are tryin' to acomplish.
In other words when adding an item, you say "If this is the first time to add, then this is my 'head' of the list, else - insert it into the 'tail' of the list". Printing is with the same idea - print the "head" and then call the tail's print method (in your code 'Show' method).
First, this is certainly not how System.Collections.Generic.List<T> works. It uses an array internally, not a singly-linked list as you do. LinkedList<T> is somewhat similar to your collection, except it uses a doubly liked list.
Now, onto your issue. The problem with your collection is that it is not able to represent an empty value and it seems you want that. What I would suggest is to create another public class that represents the whole collection and change your Collect<T> only to an internal implementation (let's call it Node<T>). This way, the new collection class can contain null reference to Node<T>, when it is first constructed, which signifies an empty collection.
If this were production code, I'm pretty sure you would actually need to do something like this, because you are going to want to keep some information on a per-collection basis (like count).
Another option (which is usually taken by lists in functional languages) is to create an inheritance hierarchy similar to the following:
abstract class Node<T>
{ }
class FullNode<T> : Node<T>
{
public T Item { get; private set; }
public Node<T> Next { get; private set }
// constructor and possibly other members
}
class EmptyNode<T> : Node<T>
{ }
This way, you have separate types to represent a full node and an empty node. In those lists, it is usual to add new items to the front, not to the back, though.
I would suggest at least one other improvement, regarding the speed of adding, but I suppose your book will get to that.
Also, I'm quite sure this is the case, but I really hope you're not planning on using this code in any kind of production environment and that it is just an learning exercise.
Just to add a little bit more information...
The reason the 0 is being written out is because you have a != null check on the firstObject. Obviously, the default value of an integer is not null, it is zero, so when firstObject hasn't been set it will be zero and not null. I guess if you want to exclude any value that is not the default for that type you could change your check to:
if (firstObject != default(TItem))
That's probably not exactly what you want though as I'm sure zero could be a valid value in this instance.
Try a nullable type
Collect<int?> test = new Collect<int?>();