Confusion: Internal, Protected and Protected Internal [duplicate] - c#

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the difference between 'protected' and 'protected internal'?
What is the difference between Public, Private, Protected, and Nothing?
Code is as mentioned below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace testanotherlib
{
public class A
{
internal void InternalDisplay()
{
Console.WriteLine("Internal Display Method.");
}
protected void ProtectedDisplay()
{
Console.WriteLine("Protected Display Method.");
}
protected internal void ProtectedInternalDisplay()
{
Console.WriteLine("ProtectedInternal Display Method.");
}
public void PublicDisplay()
{
Console.WriteLine("Public Display Method.");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace testanotherlib
{
public class B : A
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using testanotherlib;
namespace testlib
{
public class C:A
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using testlib;
using testanotherlib;
namespace testapp
{
class Program
{
static void Main(string[] args)
{
B objB = new B();
C objC = new C();
}
}
}
I am trying to understand the difference between Internal, Protected and Protected Internal. For that I have created an example using the code above.
In a class library project testanotherlib I have class A & class B. In a class library project testlib I have class C. The program class is in a separate console application. Inside the main method of Program class I have created object for class B (objB) and class C (objC). For objB and and objC only the public method of class A are accessible. I was expected for class B all the methods of class A will be accessible. Kindly help me to understand this. If you need any other information about the project, feel free to ask me.
Regards,
Priyank

The following five accessibility levels can be specified using the access modifiers:
public: Access is not restricted.
protected: Access is limited to the containing class or types derived from the containing class.
Internal: Access is limited to the current assembly.
protected internal: Access is limited to the current assembly or types derived from the containing class.
private: Access is limited to the containing type.
Taken directly from Microsoft's MSDN library.

internal
Only visible in the current and friendly assemblies.
protected
Only visible within classes that inherit A.
protected internal
Visible within classes that inherit A. And also visible within the current and friendly assemblies.

protected methods and members can only be accessed from another Class that derives from the class declaring the procted method.
class A
{
protected void Method() {}
}
class B : A
{
public void Foo()
{
Method(); // works!
}
}
class C
{
public void Foo()
{
Method(); // won't work, obviously
var tmp = new A();
tmp.Method(); // won't work either because its protected
}
}
internal makes the method only visible in the same assembly. For classes in the same assembly the method can be used like it were public. for classes outside of your current assebmly its like private.
Now combining protected and internal makes a method usable in the same assembly for all classes in that assembly. And the protected makes the method usable in all derived classes no matter which assembly.

Related

accessing a method in a dll

okay, so to start with i have set up the references in the project that i am useing the dll in.
what i am trying to do is access the method "haha" in my utils dll
code for dll
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Utils
{
public class kb
{
public class yes {
public void haha(string yes)
{
int test = Convert.ToInt32(yes);
}
}
}
}
and in the project im trying to access haha in i have just "Utils.kb.yes" but there is no method in that.. all i can do is Utils.kb.yes.equals and Utils.kb.yes.ReferenceEquals.
Since haha() is an instance method, you need to create an instance of the Utils.kb.yes class first:
Utils.kb.yes kb = new Utils.kb.yes();
kb.haha("nextproblem");
Or you also can make the method static:
public class yes {
public static void haha(string yes)
{
int test = Convert.ToInt32(yes);
}
}
then you can call it like this:
Utils.kb.yes.haha("I am static!");
Your classes do not have a constructor, and besides that, you simply CAN'T do much with a class before instantiating an object out of it. So you should reference your dll, and then create a new object first. From within that object, you can then reference your method(s).

How to derive a class from a nested interface?

The following code is not compilable:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args) { }
}
class Class : Class.Interface
{
internal interface Interface
{
}
}
}
The error message is:
error CS0146: Circular base class dependency involving 'ConsoleApplication1.Class' and 'ConsoleApplication1.Class.Interface'
Don't understand this.
Update:
This is probably more "motivating" (-;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args) { }
}
class Container : Container.Interface
{
// Everything, that is of type "Container.Interface" can be used as child here.
// ... including the container itself.
Interface[] _children;
// Is nested to keep the naming consistent.
internal interface Interface
{}
}
}
Wenn I put the interface outside of class "Container", it should be named somthing like "ContainerChildInterface". In my project I will have several classes like this, and thus several interfaces. And I think, using nested interfaces would be much better style in this case.

Problems using an interface in C#

I am trying to create a setup for a class I am making so when it is created a manager class can be setup for it, and it might require to call functions in that class via an interface
These calls are not always required, and the manager may not always be the class that called this class, so a simple return value and use it form the manager class does not meet the requirements.
What I am trying to do is following code. (Tried to strip as much unnecessary out as possible)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
interface Itester
{
void LoadTest();
}
public partial class Form1 : Form, Itester
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
World testWorld = new World();
testWorld.SetManager(this);
testWorld.InitializeWorld();
}
void Itester.LoadTest()
{
//random action I want run
label1.Text = "Ran LoadTest()";
}
}
public class World
{
Itester worldManager;
public World()
{
InitializeWorld();
}
private void InitializeWorld()
{
worldManager.LoadTest();
}
public void SetManager(Itester test)
{
worldManager = test;
}
}
}
I get this error based on it. The error refer to the "public void in the World class"
Error 1 Inconsistent accessibility: parameter type 'WindowsFormsApplication1.Itester' is less accessible than method 'WindowsFormsApplication1.World.SetManager(WindowsFormsApplication1.Itester)' XYZ Location Form1.cs 316 21 Feudal World
What I would have expected to happen was that.
Form1 class creates a local instance of the World Class, then runs its constructor (does nothing), then it sets itself as its Manager (could in theory be another class implementing the Itester interface), finally it calls the World Class again and ask it to initialize the world, where I would have expected the world class to call the Form1 instance and have it update the label on the button.
lvl1:Form1 -> lvl2:World -> lvl3:Form1(or other manager) -> return void to lvl2:World -> return void to lvl1:Form1
What am I missing, why does this not work?
Your interface does not have accessibility modifier, so it is assumed internal. Change it to public:
public interface Itester
{
void LoadTest();
}
The reason you need to do this is because the method SetManager is public, thus anyone that can consume the SetManager method must also be able to see the interface.
now I just need to figure out why it works
Consider that SetManager can be called from any assembly because it is public. So if someone were creating an assembly, they could reference yours and call worldInstance.SetManager. Let's call that assembly BigHappyAssembly.
Now consider the first parameter of SetManager is ITester, however it is internal. When BigHappyAssembly tries to call SetManager, it would be presented with a problem: What am I suppose to give as the first parameter? It doesn't have access to the ITester type, so it doesn't know that is what the first parameter is.
To prevent this happening in the first place, the compiler stops you from introducing this problem. It's warning you that you have created a public member, that anyone can call, however not everyone will be able to know what the parameters are.

C# subclass while maintaining name. Deep voodoo?

I have a dll that I'm working with, it contains a class foo.Launch. I want to create another dll that subclasses Launch. The problem is that the class name must be identical. This is used as a plugin into another piece of software and the foo.Launch class is what it looks foe to launch the plugin.
I've tried:
namespace foo
{
public class Launch : global::foo.Launch
{
}
}
and
using otherfoo = foo;
namespace foo
{
public class Launch : otherfoo.Launch
{
}
}
I've also tried specifying an alias in the reference properties and using that alias in my code instead of global, that also didn't work.
Neither of those methods work. Is there a way I can specify the name of the dll to look in within the using statement?
You'll need to alias the original assembly and use an extern alias to reference the original assembly within the new one. Here's an example of the use of the alias.
extern alias LauncherOriginal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace foo
{
public class Launcher : LauncherOriginal.foo.Launcher
{
...
}
}
Here's a walkthrough that explains how to implement that.
Also, you'd mentioned that you tried to use an alias before and encountered problems but you didn't say what they were, so if this won't work then please mention what went wrong.
as Chris said, you can use an alias on your original assembly.
If you can't you that, then you might be able to cheat by using a 3rd assembly
Assembly1.dll (your original)
namespace foo {
public class Launch {}
}
Assembly2.dll (dummy)
namespace othernamespace {
public abstract class Dummy: foo.Launch {}
}
Assembly3.dll (your plugin)
namespace foo{
public class Launch: othernamespace.Dummy{}
}
I'm not even proud of this!
Class name can be identical if it's defined in another namespace, but it boggles the mind why anybody would want to do that to themselves.
Maybe you need to use extern aliases.
For example:
//in file foolaunch.cs
using System;
namespace Foo
{
public class Launch
{
protected void Method1()
{
Console.WriteLine("Hello from Foo.Launch.Method1");
}
}
}
// csc /target:library /out:FooLaunch.dll foolaunch.cs
//now subclassing foo.Launch
//in file subfoolaunch.cs
namespace Foo
{
extern alias F1;
public class Launch : F1.Foo.Launch
{
public void Method3()
{
Method1();
}
}
}
// csc /target:library /r:F1=foolaunch.dll /out:SubFooLaunch.dll subfoolaunch.cs
// using
// in file program.cs
namespace ConsoleApplication
{
extern alias F2;
class Program
{
static void Main(string[] args)
{
var launch = new F2.Foo.Launch();
launch.Method3();
}
}
}
// csc /r:FooLaunch.dll /r:F2=SubFooLaunch.dll program.cs

How to correct warning CS1707?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Collections;
using System.ComponentModel;
namespace ConsoleApplication1
{
class BreakingChange
{
delegate void SampleDelegate(string x);
public void CandidateAction(string x)
{
Console.WriteLine("Snippet.CandidateAction");
}
public class Derived : BreakingChange
{
public void CandidateAction(object o)
{
Console.WriteLine("Derived.CandidateAction");
}
}
static void Main()
{
Derived x = new Derived();
SampleDelegate factory = new SampleDelegate(x.CandidateAction);
factory("test");
}
}
}
\Program.cs(32,38): warning CS1707: Delegate 'ConsoleApplication1.BreakingChange.SampleDelegate' bound to 'ConsoleApplication1.BreakingChange.Derived.CandidateAction(object)' instead of 'ConsoleApplication1.BreakingChange.CandidateAction(string)' because of new language rules
\Program.cs(23,25): (Related location)
\Program.cs(16,21): (Related location)
Question:
I know what causes this warning and know the reason behind it. However, I don't know what the
best way to fix it?
1> Redefine the function (i.e.) change the function signature
2> Can we explicitly call BreakingChange.CandidateAction in the following line?
SampleDelegate factory = new SampleDelegate(x.CandidateAction);
Well, there are multiple ways to "fix" this, depending on what you want to, and can, do.
Personally I would add another overload to Derived that took a string, since you're going to have the same issue with non-delegate calls as well.
public class Derived : BreakingChange
{
public new void CandidateAction(string x)
{
base.CandidateAction(x);
}
public void CandidateAction(object o)
{
Console.WriteLine("Derived.CandidateAction");
}
}
Or, since you know you want the base class method, you can cast the reference x:
new SampleDelegate(((BreakingChange)x).CandidateAction)

Categories

Resources