I'm having some trouble understanding access modifiers; I want to know better when to use what level of access, especially for properties--just links to good tutorials on that subject could be its own question.
But more specifically, I don't understand why an object bound to a WinForm control has to be public. So I create my object:
public class Foos : List<Foo>
{
}
public class Foo
{
private int bar;
public int Bar
{
get { return bar; }
set { bar = value; }
}
}
then bind it to a DataGridView
public partial class Form1 : Form
{
private Foos formFoos;
public Form1()
{
InitializeComponent();
formFoos = new Foos();
AddFoo();
dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = formFoos;
}
/// <summary>
/// generate some test values
/// </summary>
private void AddFoo()
{
for (int i = 1; i <= 5; i++)
{
Foo foo = new Foo();
foo.Bar = 5 * i;
formFoos.Add(foo);
}
}
}
Works fine. But what if I don't want to expose Foo.Bar outside my assembly? If I make it internal int Bar I get an empty dataGridView1. If I make it protected I get a compiler error, because of course Form1 is not derived from Foo.
How does a control in a form in my program not match the definition of internal though?
Internal members are accessible only within files in the same
assembly.
General wisdom on how you make these declarations in a systematic way also welcomed.
You should mark the whole Foo class as internal.
This way, the entire Foo class and all it's members will be invisible outside the assembly.
Form1.dataGridView1 needs Foo.Bar to be public, otherwise it won't be able to make use of it.
Now, because Foo is already marked internal, it can expose Bar as public with no risk of exposing it outside the assembly.
This should make both Form1.dataGridView1 and you equally happy.
Please note that by marking Foo as internal, Foos should also change from public to internal because Foos may not have a higher access level than the class it's derived from.
Related
When I define a class inside my c# windows application project, the class is supposed to be internally available to the project.
So I should be able to declare that type of class from within my form, without defining my class as a public class.
But I am getting an accessibility error, which goes away when my class is redefined as public, instead of the default (which is supposed to be internal to the assembly).
This is not a repeat question. This question differs from other accessibility issues I have seen.
All items in my project (forms, classes, etc.) should belong to the same assembly, so what's going on?
Is default scope of class internal or not? Research says its supposed to be internal, so this code is supposed to work....
I get...
"Inconsistent accessibility. Field type Queue is less accessible than Form1.Queue"
See code below.
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Queue Queue; // <-- PROBLEM LINE
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
}
}
}
here is the definition of queue; i don't think its really important, but it was requested by a commenter; when I make the class Public, all problem is solved. But that doesn't make sense if the default scope is supposed to be internal, it should not force me to make public:
namespace WindowsFormsApplication3
{
class Queue
{
private const int DEFAULTQUEUESIZE = 100;
private int[] data;
private int head = 0, tail = 0;
private int numElements = 0;
public Queue()
{
this.data = new int[DEFAULTQUEUESIZE];
}
public void Enqueue(int item)
{
if (this.numElements == this.data.Length)
{
throw new Exception("Queue full");
}
this.data[this.head] = item;
this.head++;
this.head = this.head % this.data.Length;
this.numElements++;
}
public int Dequeue()
{
if (this.numElements == 0)
{
throw new Exception("Queue Empty");
}
int queueItem = this.data[this.tail];
this.tail++;
this.tail = this.tail % this.data.Length;
this.numElements--;
return queueItem;
}
}
}
So by adding some guesswork to your question, if the type in question is
internal class Queue
then, quite obviously,
public Queue queue;
is an error - you have a public field of an internal type. How would you expect that to work? The problem is not that your Form has no access to Queue. It's that something from outside your project has access to the Form, has access to the public field, but it does not have access to the type of that field. That makes no sense, how do you expect an external class to make sense of a field whose type it cannot access?
If you declare the Queue as public - the problem goes away, the type is now externally visible.
If you declare the field as internal (or even private) - the error also goes away, as anything accessing that field also has access to the type.
I hope this explains the issue. On a side-note: declaring public fields is usually a mistake, if you want it to be accessible from the outside, use a property:
public Queue Queue {get; set;}
Your Form is declared public and contains a public field of your Queue class. Since Queue isn't public, the compiler refuses to compile your code. If you want Queue to be internal, declare the field as internal or private
I am overlooking something simple I think. I have a form with a checkbox. I need to know if the checkbox is checked in a different cs file/class to know whether to make a column header Option1 or Option2.
Form1 (Public partial class) code:
public bool Checked
{
get
{
return checkBox1.Checked;
}
}
In my Export1 class I have private void CreateCell1 that takes in the data to be exported (creating an excel file from a datatable). The section of code I can't get to work is:
if (Form1.Checked.Equals("true"))
{
newRow["Option1"] = date2;
}
else
{
newRow["Option2"] = date2;
}
I am getting -Error 1 An object reference is required for the non-static field, method, or property 'Matrix1.Form1.Checked.get'
What did I overlook?
Well, the problem here is exactly what the compiler is telling you. You need an object reference in order to access the property.
Allow me to explain.
In C#, by default, class members (fields, methods, properties, etc) are instance members. This means that they are tied to the instance of the class they are a part of. This enables behavior like the following:
public class Dog
{
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
var dog1 = new Dog { Age: 3 };
var dog2 = new Dog { Age: 5 };
}
}
The two instances of Dog both have the property Age, however the value is tied to that instance of Dog, meaning that they can be different for each one.
In C#, as with a lot of other languages, there are things called static members of classes. When a class member is declared static, then that member is no longer tied to an instance of the class it is a part of. This means that I can do something like the following:
public class Foo
{
public static string bar = "bar";
}
public class Program
{
public static void Main()
{
Console.WriteLine(Foo.bar);
}
}
The bar field of the Foo class is declared static. This means that it is the same for all instances of Foo. In fact, we don't even have to initialize a new instance of Foo to access it.
The problem you are facing here is that, while Form1 is not a static class and Checked is not a static property, you are treating it as such. In order for what you are trying to do to work, you need to create an instance of Form1 and access that instance's Checked property.
Depending on how your program is structured, there are many ways of doing this. If Form1 is created in the scope where you are trying to access Checked, then this will be straightforward. If Form1 is what spawns the new scope, then common practice is to pass a reference to it in the constructor.
For example, if Form1 creates a new Form2 then we do the following:
public class Form2 : Form
{
private Form1 parent;
public Form2(Form1 parent)
{
this.parent = parent;
InitializeComponent();
}
}
And then you can access parent throughout Form2. Of course, depending on the structure of your program, the exact implementation will be different. However, the general pattern is the same. Pass the reference to Form1, from the scope it was created in, to the new class, and then access it from there.
One way or another, you need to access the specific instance of Form1 that you're trying to check.
A few ways to do this are:
Pass the instance to the class constructor
Setting a public property of the other class to the instance of the form
Pass the instance to the method directly
For example:
public class SomeOtherClass
{
// One option is to have a public property that can be set
public Form1 FormInstance { get; set; }
// Another option is to have it set in a constructor
public SomeOtherClass(Form1 form1)
{
this.FormInstance = form1;
}
// A third option would be to pass it directly to the method
public void AMethodThatChecksForm1(Form1 form1)
{
if (form1 != null && form1.Checked)
{
// Do something if the checkbox is checked
}
}
// This method uses the local instance of the Form1
// that was either set directly or from the constructor
public void AMethodThatChecksForm1()
{
AMethodThatChecksForm1(this.FormInstance);
}
}
This class would need to be instantiated by the instance form1 using one of these methods:
// Pass the instance through the constructor
var someOtherClass = new SomeOtherClass(this);
// Or set the value of a property to this instance
someOtherClass.FormInstance = this;
// Or pass this instance to a method of the class
someOtherClass.AMethodThatChecksForm1(this);
A little background on my project:
I'm making a multi-form application, which consists of 1 mainform, and 6 childforms that can be called from the mainform, but only 1 childform can be active at a time. These childforms share certain parts of code, which I do not want to copy. To solve this, I have a codefile within the same namespace which holds the nessaccary code.
This codefile however, needs access to certain properties of the currently active childform.
My search has come down to using an interface to extract the needed information from the active childform.
My code is currently looking like this:
Interface:
public interface Interface1
{
TabControl tabControl_Buizen_
{
get;
}
TabPage tabPage_plus_
{
get;
}
}
Childform:
public partial class Childform : Form, Interface1
{
Interface1 dummy;
public TabControl tabControl_Buizen_
{
get { return this.tabControl_Buizen; }
}
public TabPage tabPage_plus_
{
get { return this.tabPage_plus; }
}
Methods_newTabPage methods = new Methods_newTabPage(dummy);
}
Codefile:
public class Methods_newTabPage
{
private readonly Interface1 form;
public Methods_newTabPage(Interface1 formInterface)
{
this.form = formInterface;
}
}
As you can see I'm using Methods_newTabPage methods = new Methods_newTabPage(dummy); to be able to call methods in my codefile, but the codefile requires the interface to be passed (which I filled as "dummy"). This however pops the error "A field initializer cannot reference the non-static field, method, or property Childform.dummy".
How can I let the childforms access the methods in the codefile, while also giving the codefile access to certain controls in differing childforms?
The error is easy to fix: just make dummy static.
static Interface1 dummy;
However, I don't think that will help you much. Why are you passing this dummy to Methods_newTabPage anyway? This will lead to NullReferenceExceptions inside the code file because dummy was never initialized with anything.
Don't you rather want to pass this, i.e. the current instance of Childform?
But you cannot just exchange dummy with this like so:
// Compiler error "Keyword 'this' is not available in the current context".
Methods_newTabPage methods = new Methods_newTabPage(this);
Instead you have to add a constructor that creates Methods_newTabPage:
public partial class Childform : Form, Interface1
{
private Methods_newTabPage methods;
public Childform()
{
methods = new Methods_newTabPage(this);
}
public TabControl tabControl_Buizen_ { get { return this.tabControl_Buizen; } }
public TabPage tabPage_plus_ { get { return this.tabPage_plus; } }
}
Try adding a constructor that initializes the field methods.
Also I don't see how that dummy makes sense. Instead initialize methods via methods = new Methods_newTabPage(this); in the constructor.
In the code below I have a class Foo which is called (without an interface) by my main method. There is no backing field or setter for the property, instead it calls a private method. Foo cannot be changes, nor can the usage of foo be changed to an IFoo interface.
- How do I change the value of foo.FooValue?
- Is there anything in the System.Reflection, System.Reflection.Emit, .NET standard libraries etc (unsafe code, whatever) that I can include in a unit test to change the return value?
I appreciate if there is something it's bound to be quite "evil", but I am interested in "evil" answers.
public class Program
{
public static void Main(){
Foo foo = new Foo();
int bar = foo.FooValue;
}
}
public class Foo{
public int FooValue
{
get
{
return this.FooMethod();
}
}
private int FooMethod
{
return 0;
}
}
Related questions:
How to set value of property where there is no setter - Related but unanswered - Maybe the answer is "no", but I'm not convinced by the top answer which merely points out you can't achive this by changing a (non-existent) backing field.
Intercept call to property get method in C# - Interesting. Not sure whether this is my answer and if it is, not sure how it could be used in a unit test.
EDIT: Okay. I'm going to re-write my code to make it more testable. However, out of interest, has anyone out there successfully hacked their way through this situation?
You could create a proxy for Foo that could be mocked:
public class FooProxy : IFoo
{
private Foo _Foo;
public FooProxy(Foo foo)
{
_Foo = foo;
}
public int FooValue
{
get {return _Foo.FooValue();
}
}
public interface IFoo
{
public int FooValue {get;}
}
then you can use DI to "inject" an IFoo and make your code more testable.
Since I am building a physics teaching platform, I need to know the total force that is acting on an object at the moment. This way, I may draw arrows showing this resultant force for students to understand what is going on.
I dug into the source of Farseer and found the internal Vector2 variable Force. Since it is internal, I cannot access it from my teaching platform since they are in different assemblies.
Will anything bad happen if I change the modifier to, let's say private, and add a getter function to it?
OR
Is there a better way to get the resultant force currently acting on an object?
Since it seems you have access to the source, the easiest approach to expose that variable is to add a public getter to the class in which it resides. An instance of that class will have access to the internal variable.
EDIT: (Added code examples)
It is all about where the code accessing the internal value exists. Hopefully the example below will illustrate this for you. Assume that you have a solution with two projects, one called ExternalAssembly, the other MyApplication. MyApplication has a reference to ExternalAssembly to access its classes.
Project: ExternalAssembly
namespace ExternalAssembly
{
public class MyClass
{
internal string hiddenString;
public MyClass()
{
this.hiddenString = "This is my value.";
}
public string Exposed
{
get { return this.hiddenString; }
}
}
public class MyClass2
{
private MyClass classInstance;
public MyClass2()
{
this.classInstance = new MyClass();
}
public string Exposed2
{
get { return this.classInstance.hiddenString; }
}
}
}
Project: MyApplication
namespace MyApplication
{
using ExternalAssembly;
public class CallInternalTest()
{
MyClass classInstance = new MyClass();
MyClass2 class2Instance = new MyClass2();
// this will fail since hiddenString is an internal variable
Console.WriteLine(classInstance.hiddenString);
// this will succeed since Exposed is a public member
Console.WriteLine(classInstance.Exposed);
// this will also succeed since Exposed2 is a public member
Console.WriteLine(class2Instance.Exposed2);
}
}