How do you access data in another class in C#? - c#

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.

Related

C# Get class declaration name

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.

C# accesing non static member in a static function

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.

C# What is the difference between creating a static object outside a class VS creating it inside a class?

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.

Get a List of Generic Types Applied to Any Class

I have a particular need which I cannot seem to figure out. I've done some research into this, but cannot find a feasible solution.
I have a base class:
public abstract class BaseProvider<T> {}
this class in turn is inherited by two different provider classes:
public sealed class MonkeyProvider<T>
: BaseProvider<MonkeyProvider<T>>
where T
: IAnimalProvider
Within in the interface IAnimalProvider I expose a single property that all implementations must derive off. Now, MonkeyProvider and maybe DonkeyProvider or something similar needs to know what the assigned value for the property the root instance is:
public class JoburgZoo
: IAnimalProvider
{
#region IAnimalProvider members
public string Id{ get; set; }
#endregion
}
// somewhere in a console application
public static void Main(string[] args)
{
JoburgZoo zoo = new JoburgZoo();
zoo.Id = "Mammals";
**// edit: an instance of the provider will be created**
MonkeyProvider<JoburgZoo> mp = new MonkeyProvider<JoburgZoo>();
mp.CheckMonkeys(zoo); // where CheckMonkeys(JoburgZoo) is a method in the provider
}
Now, here is my actual question:
I have the need to expose an internal property through BaseProvider which every instance that implement it, has access to. This property needs to return the value of "Id" at any given point, but I cannot seem to be able get the value through reflection (which I know is the solution to this).
From my various fruitless efforts:
Type type = typeof(T); // this returns BaseProvider<MonkeyProvider<T>>
var generic = type.GetGenericTypeDefinition(); // brings back BaseProvider<T>
I can't create a new instance of T as it will clear all values currently assigned to the object. I can't iterate the property info collection, as that will only return the properties of BaseProvider.
Thanks for any help on this.
Eric
// Edit.
Added an additional call in the console main code above. the instance of MonkeyProvider<T> templates JoburgZoo, so in ProviderBase<T> it will look something like:
ProviderBase<MonkeyProvider<JoburgZoo>>
I want to know what the properties of JoburgZoo is, from within the BaseProvider<T> without the need to identify the object withing MonkeyProvider<T>.
Hope this makes sense.
With following class definition,
class BaseProvider<T>
{
//...
}
following code returns System.Int32 :
Type type = typeof(BaseProvider<Int32>);
foreach (var arg in type.GetGenericArguments())
{
MessageBox.Show(arg.FullName);
}

Sharing a reference between objects

I want to have multiple objects share a reference through a private field, such that any of the objects can assign to the field, and the updated field will be seen by other objects sharing that reference. What I was originally hoping to do was this:
class SomeObject
{
private ref DataObject _data;
public SomeObject(ref DataObject data)
{
_data = ref data; // or something similar
}
public ChangeData(DataObject newData)
{
_data = data;
// at this point, *other* SomeObject instances that were
// created with the same reference should also have _data == newData
}
}
But of course you can't use ref that way: ref is only for method parameters. And a static field won't work, since not all SomeObject instances should refer to the same object---rather, the object in question should be set in the constructor.
Obviously I could solve this by just adding a simple wrapper class. But is there a better way? Is there some kind of SharedReference<T> class that I can use?
Update, since most of the answers misunderstood what I was asking. I know that the _data field contains a reference to the original DataObject. What I want is another level of indirection. I want to be able to change which object I'm pointing to in one instance, and have the new value be picked up by other instances that were created with the same reference. As the updated code sample shows, I want to assign to _data, and effectively change the value of _data in other instances.
I don't know of any class that you can use for this, but I seems quite easy to implement your own SharedReference<T> class.
Something like this:
public sealed class SharedReference<T>
where T : class
{
public T Reference
{
get; set;
}
}
You could simply use an array of shared objects, and reassign the array elements:
class SomeObject
{
// you probably want to make this readonly
private readonly DataObject[] _data;
public SomeObject(DataObject[] data)
{
_data = data;
}
public void ChangeData(DataObject newData)
{
_data[0] = o;
}
// and you could define your own accessor property...
private DataObject Data
{
get { return _data[0]; }
set { _data[0] = value; }
}
}
Apart from that, I think you'll need to define your own 'holder' class & use that
If you simply provide a reference to the object without the ref keyword, you will get the behaviour you want. Using ref is actually passing a reference to a reference (pointer to a pointer), so unless you want to null someone else's reference, it won't be of any use to you.
Update: Sorry I didn't spot that you wanted to re-assign a completely new object into the field and have that reflected throughout. You are best actually creating either a wrapper class to contain the object state and modify that, or a common event that all instances can subscribe to such that when you want to change the object, fire the event with the new object inside it and have each instance update it's own internal reference.
Alternatively, use the Singleton pattern - everyone accesses a publicly available static reference, but unlike the traditional Singleton, you let them change the reference if they want to - so everyone can see the change. This also has the benefit that the objects don't need internal references.
Alternatively again, have the data class expose a method allowing it to consume another data class and copy its state across - like cloning.
In C#,
class SomeObject
{
private DataObject _data;
public SomeObject(DataObject data)
{
_data = data;
}
}
in fact does exactly what you want, if DataObject is a Reference Type, which is true for all classes.
Please disregard this answer since I misunderstood the initial question.Other answers here cover the topic fully.

Categories

Resources