So I have a function:
List<string> names = new string();
private static void getName(string name)
{
names.add(name);
}
When I attempt to compile I get a:
'object reference is required for the non-static field' notice.
What do I have to do to make this member (names) compatible with getName?
I need it to be non static or converted because I want to put the results into other non static functions and forms.
You need to tell the system which list of names you're interested in. It's part of the state of an object, an instance of the class... but which one? Maybe you've created several instances of the class - maybe you've created no instances of the class. The static method has no visibility of that - so which instance do you want it to fetch the names variable value from?
To put it in another example, suppose we had a class like this:
public class Person
{
public double MassInGrams { get; set; }
public double HeightInMetres { get; set; }
public static double ComputeBodyMassIndex()
{
// Which person are we interested in?
}
}
Person p1 = new Person { MassInGrams = 76203, HeightInMetres = 1.8 };
Person p2 = new Person { MassInGrams = 65000, HeightInMetres = 1.7 };
double bmi = Person.ComputeBodyMassIndex();
What would you expect the result to be? You've asked the Person class to compute "the BMI" but without telling it whose BMI to compute. You need to give it that information.
Some options for your situation:
Change names to be static instead
Change the method to be an instance method
Pass in an instance of the class
Create an instance of the class, possibly returning it
Fetch an instance of the class some other way
By the way, that's a very strange method name for something which adds a name. It's also somewhat unconventional...
You need to make names static if you want to use it from inside of a static method:
// If this is static, you can use it from your static method
static List<string> names = new List<string>();
The issue is that getName is defined on your type, not on an instance of the type. However, names is defined so each instance of your type gets its own value.
names is an object that will exist in the instances of the class e.g. MyClass mc = new MyClass(); then you can access mc.names. A static field can be called without an instance of the class just with the classname, e.g. MyClass.getName(""); will work. So when you think logically, the class doesn't contain names, only 'the instances of that class' contain it. Therefore, you either make that list static too and it will be 'the same List instance' everywhere when you call MyClass.names or make the getName method non-static, and it will be only called from instances, therefore no MyClass.getName("") will be possible, but mc.getName(""); It's a matter of what you are exactly trying to do.
Static methods can not access class fields. Either make names static, or make getName() non-static. What do you mean by "Compatible". Ask yourself... does the method need to be static? What is its purpose and how do you intend to use it?
You cant access it this way, you need to instanciate the class containing a member.
Related
Is it possible to get the declaration name of a class (dynamically) and pass it as a parameter in the constructor to set the name variable in the class itself?
Example:
public class Foo
{
public string name;
public Foo()
{
name = GetClassName();
}
}
public class SomeOtherClass
{
Foo className = new Foo();
Console.WriteLine(foo.name);
}
As result I would expect it to write: "className".
No. That is not possible. There is no way to pass in a variable name without using a parameter.
This is the closest you can get:
Foo className = new Foo(nameof(className));
That sounds like a weird requirement. A variable is nothing but a reference to an object. The name of that reference has by no means anything to do with what this variable reference. Thus the actual referenced object doesn´t know anything about its references. In fact you may have even multiple references to the same Foo-instance. So how should the instance know to which variable you refer to? So what should happen in the following example:
var f = new Foo();
var b = f;
Now you have two references to the same instance of Foo. The instance can´t know which of hose is the right, unless you provide that information to it by using a parameter (e.g. to your constructor). The thing gets even worse if you have a factory creating your Foo-instance:
void CreateFoo()
{
return new Foo();
}
// ...
var f = CreateFoo();
Now you have a further indirection, the constructor of Foo can surely not bubble though all layers in your call-stack until it reaches some assignement where it may get the actual name. In fact it´s possible that you don´t even assign your instance to anything - although this is merely a good idea:
CreateFoo(); // create an instance and throw it away
Anyway if you want to set a member of an instance to some value, you should provide that value to the instance. The answer by Patrick shows you how to do so.
I have three objects :
private static readonly Apple a, c;
private readonly Orange b;
This code is called from my constructor :
public SomeClass()
{
a = new Apple();
b = new Orange(a.getDna());
c = new Apple(b.getDna());
}
It gives me the error Readonly field cannot be used as an assignment target. If I remove either the static or readonly modifiers, it compiles perfectly. (Is there a wrong warning here?)
On checking other answers here on SO, I found that I should use a static constructor like :
static SomeClass()
{
a = new Apple();
c = new Apple(b.getDna());
}
public SomeClass()
{
b = new Orange(a.getDna());
}
But this would cause the static constructor to be called first and cause an error since b would not be initialized.
How do I circumvent this?
P.S. I'm relatively new to C#
Let's start by defining what is static and what's the difference between static and instance members.
A static member is a member that doesn't need an instance to exist: it "belongs to the class", and not to an object (a instance of the class).
Now the readonly modifier, says that a member can only be assigned a value in the constructor (or in its declaration, but that's not relevant here).
There are two types of constructors: static constructors and instance constructors... the difference is the same difference as above, and the readonly modifier is of course, applied to each type of constructor: static readonly would mean "you can only change its value in the static constructor", and instance readonly would mean "you can change its value in the instance constructor".
The static constructor is called the first time the type is accessed, so it's always called first.
Now, in the examples you are just randomly changing members to static or not just to try if it compiles.
Think about it for a second... in the static context you have no instance at all, so it's just not possible to access instance members on the static constructors... furthermore, by the time the static constructor is called, there's no way you could have any initialized instance, even externally defined, since it'll always be called before you have the chance to initialize one.
So this line within the static constructor makes no sense:
c = new Apple(b.getDna());
You are trying to access b, which is an instance member, but you are not saying which instance should you get the value from.
You should really rethink your design, and think why members would be static or not, not just "move things around and try to make it compile and run".
The error is correct because if you create another instance of SomeClass the static field a will be assigned twice, against the readonly constraint.
You are trying to assign values to read only static variables inside a instance constructor. At the point you call the instance constructor that variables are already assigned a value, which is null.
public SomeClass()
{
a = new Apple(); // it is already assigned as null.
b = new Orange(a.getDna()); //there is no value assigned to it yet
c = new Apple(b.getDna()); //it is already assigned as null
}
This happens because the static constructor is called before the instance constructor. You can have more details here:
A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.
But then, you have the problem when you are trying to access an instance variable inside the static constructor. At that point, the instance constructor is not yet called, which means your variable b is not yet initialized.
You are facing a very common problem, where you are trying to mix instance variables and static variables. This approach can lead to very strange behaviours, like the one you are facing.
I suggest to you to don't mix this variables, make them all static or or make them all instance, but don't mix it. Otherwise, you might face different problems in the near future
The error message is in fact correct.
First, static means it belongs to the class. Non static means it is per instance. An instance method can modify a static variable, but a static method cannot modify an instance variable (which instance would it modify?)
Given that, readonly means you can only initialize during creation (e.g. constructor.)
You are getting the error because you are trying to assign a readonly static AFTER its creation in an instance constructor.
Is there a wrong warning here?
No. The warning is correct. If a field is readonly, we can assign it a value in two places: upon declaration or in the constructor. Further, if something is static, its associated constructor is static too. So, we can assign to a static and readonly field in two places:
Upon declaration or
in the static constructor.
We cannot do it in an instance constructor.
Your other question is about the inability of a static field to depend on an instance one.
How do I circumvent this?
Here is a creative way to circumvent it:
In the static constructor, assign to static _b.
In the instance constructor, assign the static _b to the instance's b.
We can even assign _b = null when we're done with it and still access the value that we earlier assigned to b.
Here is an example:
public class SomeClass
{
private static readonly Apple a, c;
private static Orange _b;
private readonly Orange b;
static SomeClass()
{
a = new Apple();
_b = new Orange(a.getDna());
c = new Apple(_b.getDna());
}
public SomeClass()
{
b = _b;
_b = null;
}
//
// the rest is just class definitions
//
public class Apple
{
public Apple(object o = null) {}
public object getDna() { return new object(); }
}
public class Orange
{
public Orange(object o = null) { }
public object getDna() { return new object(); }
}
}
It does let you circumvent the problem.
I want to understand the difference between 3 sets of snippets below:
private static FirstObject o = new FirstObject();
public class ClassA
{
}
//-----------------------------------------------------
public class ClassA
{
private static FirstObject o = new FirstObject();
}
//-----------------------------------------------------
public class ClassA
{
private static FirstObject o;
public ClassA
{
o = new FirstObject();
}
}
Please help me understand in terms of scope, memory, performance and usage of these.
Thank you.
Invalid, as you can't have a variable outside of object
The proper way - the class has a static member, which is initialized when the class is accessed for the first time
Very bad, because every time when new object is created the static object will be recreated.
The first option will not compile. A static variable in C# must be scoped to a class or struct.
The second option is the preferred mechanism.
The third option is wrong because this creates a new FirstObject each time an instance of ClassA is created, which is almost certainly not what you want.
A fourth option would be to leverage a static constructor, e.g.,
public class ClassA
{
private static FirstObject o;
static ClassA
{
o = new FirstObject();
}
}
This option is useful if there is some special construction constraints for FirstObject. In this example, though, choose option 2 over option 4. Just know that option 4 exists.
Three cases below...
Assuming a typo here missing some outer construct... "o" is declared so that it will be globally accessible, as a single object, to the entire application. It will have one common set of all properties and data. It can be access directly by "Namespace.o"
"o" is declared so that it will be globally accessible, as a single object, to the entire application, However it is only accessible through another defined instance of "ClassA". Each separate instance of ClassA will have the same, single "o" object with the same properties and data.
This doesn't look right to me, I'm assuming "ol" is supposed to "o;". Even with this the code looks like its missing something. if the Line "o = new FirstObject" is correct it is not accessible in this fashion.
I need to share data between classes in C#. Sounds easy enough. I have a collection that is loaded with data in a class. Let's say it is defined like this:
public class AppAdmin: IApplicationThingy
{
public ObservableCollection<Data> DataCollection;
Now, in another class, I want to look at DataCollection. Both classes are in the same namespace. AppAdmin.DataCollection does not work. Can you help?
You have to have an instance of AppAdmin to access DataCollection
var appAdmin = new AppAdmin();
var data = addAdmin.DataCollection;
or if the design permits, you can make DataCollection static
public class AppAdmin: IApplicationThingy
{
public static ObservableCollection<Data> DataCollection;
and then you can access DataCollection as you mention in the question by
var data = AppAdmin.DataCollection;
By the looks of it, you are trying to access an instance member like a static member. Static members are attached to the class/type and and instance member is attached to an object. If you are looking to access the "DataCollection" as you have it above, you will need to create an AppAdmin object first and then you should be able to access it.
Try this.
var aAdmin = new AppAdmin();
var collection = aAdmin.DataCollection;
AppAdmin.DataCollection is an instance member of AppAdmin. This means that you need an instance of AppAdmin to access AppAdmin.DataCollection for a particular instance.
Thus, at some point you need a reference (be it through a variable of type AppAdmin or an expression that evaluates to an instance of AppAdmin) to be able to access AppAdmin.DataCollection for a particular instance.
So, somehow, someway, you need
AppAdmin appAdmin = // expression that evaluates to an instance of AppAdmin
var dataCollection = appAdmin.DataCollection;
or
var dataCollection =
(expression that evaluates to an instance of AppAdmin).DataCollection
to get a reference to AppAdmin.DataCollection for a particular instance of AppAdmin.
Let's put it more simply:
class Dog {
public IEnumerable<DogLeg> Legs { get; set; }
}
A Dog has Legs. To be able to get a particular Dog's Legs, you need an instance of Dog to receive the request for its Legs.
Similarly, an AppAdmin has a DataCollection. You need a particular instance of AppAdmin to receive the request for its DataCollection.
So, to access an instance member (be it a field, property or method) you need an instance object to receive the request.
You have to instantiate the object and then call the data filed.
AppAdmin aa = new AppAdmin();
aa.DataCollection;
You need to have an instance of the class in order to access its members.
In order to share the data in the instance, you need to pass it around:
// in one object that needs the object
var myAppAdmin = new AppAdmin():
var myData = myAppAdmin.DataCollection;
// call to another object, passing in the class
myOtherClass.GetDataFromAppAdmin(myAppAdmin);
Maybe you want to make it static?
public class AppAdmin: IApplicationThingy
{
static public ObservableCollection<Data> DataCollection;
Depends...
If the data just needs to always be available outside of any given instance of the object, just make it static:
public static ObservableCollection<Data> DataCollection;
If the data is tied to an instance of the object, then you access it from the instance and not from the class:
var myObj = new AppAdmin();
myObj.DataCollection ...
But keep in mind the difference between static and instance values. It's an important subject to learn. Trying to mix the two often leads to strange bugs.
I am not sure how to implement what I have in mind using C# .Net 3.5. I have a static class called Common which contains common methods. One of the method is PrepareReportParameters. This method accepts a string ReportParams and parse it to get the parameter values. I load this ReportParams string into a Dictionary . And then verify whether the required elements exist. I check that like:
if (ReportParamList.ContainsKey("PAccount"))
{
ReportParamList.TryGetValue("PAccount", out PrimaryAccount);
}
where PrimaryAccount is a static variable in my Common class. And I can access this elsewhere as Common.PrimaryAccount.
Though, this approcah of accessing the report parameters will work but I want PrimaryAccount to be accessed as Common.ReportParameters.PrimaryAccount.
Here is the problem, I don't know what type ReportParameters should be and how can I have all the report parameters added to this type? How should I define ReportParameters? Does it sound feasible or it doesn't make any sense. Please H E L P!
It sounds like you're basically used to using global variables to pass around state. That's generally a really bad idea.
Why doesn't your method just return the primary account value? That can then be passed to other things which need it.
If you find yourself with a lot of static members - and in particular if other classes are fetching mutable static variables - consider whether there's a more OO design you could apply. It'll be easier to understand, easier to test, and easier to maintain.
EDIT: Okay, so currently you have:
public static class Common
{
public static int PrimaryAccount;
// other static fields
public static void PrepareReportParameters(string reportParameters)
{
// Code to set the fields
}
}
Instead of that, use a normal class:
public class ReportParameters
{
public int PrimaryAccount { get; private set; }
// Other properties
private ReportParameters(int primaryAccount, ....)
{
this.PrimaryAccount = primaryAccount;
}
// Could use a constructor instead, but I prefer methods when they're going to
// do work
public static ReportParameters Parse(string report)
{
// Parse the parameter, save values into local variables, then
return new ReportParameters(primaryAccount, ...);
}
}
Then call this from the rest of your code, and pass the ReportParameters reference to anything that needs it.
You could create a class called ReportParameters with the relevant strongly-typed properties, and give Common a static instance of it?
I'm not sure this is the best design. Theres a certain amount of 'code smell' to having Common.PrimaryAccount only to be allowed to be accessed after PrepareReportParameters is called. Maybe you'd consider an instance class, passing in the parameters in the constructor?