This question is a continuation of the following question:
Basic OOPs related query
How can I ensure that OutputClass object can be created only inside the same file (api.cs), i.e.
OutputClass object1 = new ObjectClass(3);
Whereas the user of the API should not be able to create a new storage for this class, rather only be able to reference to it when it is provided from the API, i.e. the user of API should be able to do only the following:
OutputClass object1
whereas if he tries to create a new ObjectClass, it should not be possible.
You can make the constructor internal or private:
public class OutputClass
{
internal OutputClass()
{
}
}
internal means that it can be called from any class in the same assembly (not just the .CS file). private means that it can only be called from within that class (usually through a static factory method).
You can declare the constructor of OutputClass as private, assuming there is some mechanism within that class to create an instance. Otherwise an internal modifier might be more appropriate.
class OutputClass
{
private OutputClass()
{
// inaccessible to anything but OutputClass methods
}
}
Related
I met a task in which it is necessary to create an instance of an abstract class using reflection on C#. At the same time, it is forbidden to create heirs.
It is clear that it is forbidden to create such instances, but reflection helps to overcome this. The answers were advised to look in the source codes on the referencesource site, to look for something like an internal call to the constructor through reflection.
A hint in the task: need to find a method in the framework that directly deals with calling the constructor and simulate its logic without unnecessary checks. But I can't find. I find how to create instance of abstract class, but without initializing variables.
How can create such an instance so that class variables with values, if they exist are also initialized?
As mentioned in the comments, you can call the internal RuntimeTypeHandle.Allocate method to create an instance of an abstact class. Afterwards you can actually call the constructor. Calling an abstract method will throw a System.BadImageFormatException "Bad IL format." This allocate method only exists in the .Net Framework.
abstract class C
{
public string One;
public C()
{
One = "One";
}
public abstract void Abstract();
}
internal class Program
{
static void Main(string[] args)
{
var obj = (C)typeof(RuntimeTypeHandle).GetMethod("Allocate", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[] { typeof(C) });
typeof(C).GetConstructor(Type.EmptyTypes).Invoke(obj, new object[0]);
// outputs "One"
Console.WriteLine(obj.One);
// throws BadImageFormatException
obj.Abstract();
}
}
Another horrible unsafe option to somehow obtain an instance of an abstract type could be to rewrite an existing objects type information, see: https://github.com/IllidanS4/SharpUtils/blob/master/Unsafe/Chameleon.cs
This is not possible, not even with reflection. You'll get a runtime error, as demonstrated in the comments. What is possible, is creating a proxy from an abstract class (e.g. using Castle.Core). But that is still not creating an instance of an abstract class, but dynamically creates an implementation for the abstract members. And then creates an instance of that dynamically created implementation.
I'm having a hard time making this work.
The 3 classes FooType, WebApp & IWebApp must not be accessbile \ visible outside of this DLL. So hence the sealed & internal classes.
Issues I'm having are ...
1) In WebApp class, FeeType1 is not accessible in RouteOneBuilder method's parameter.
2) In WebApp class, FeeType1 is not accessible \ visible in switch's case-statement. (need to be visible).
3) In WebApp class, CreditApplication of FeeType1 property is not visible in the switch's case-statement (need to be visible).
Is there a better way to this complicated script? Am I already screwed for exposing classes outside of this DLL? Can all of step 1 to 4 be resolved differently (or be fixed somehow)?
I don't see how can I make this any simplier.
internal static class FooType
{
public class FeeType
{
public FeeType() { }
public string CreditApplication = "Credit Application";
public string CreditVehicle = "Credit Vehicle";
}
public FeeType FeeType1
{
get { return new FeeType(); }
private set { }
}
}
sealed class WebApp : IWebApp
{
public string RouteOneBuilder(FooType.FeeType1 typing)
{
var xml = "";
switch(typing)
{
case FooType.FeeType1.CreditApplication:
xml = "asdf";
break;
default:
throw new Exception("Unknown value");
}
return xml;
}
}
internal interface IWebApp
{
string RouteOneBuilder(FooType.FeeType typing);
}
Your definition of a sealed class is incorrect. It is not an access modifier like public, private, protected and internal. Marking a class sealed only says that it cannot be inherited from; it does not say anything about access per se.
From the MSDN documentation:
When applied to a class, the sealed modifier prevents other classes
from inheriting from it.
That means that you can still provide a public class that is sealed. However, if you try to inherit from a sealed class, you will receive a compiler error like this:
cannot derive from sealed type 'YourNamespace.YourSealedClass'.
Also, I suggest you read this and this regarding internal/public and nested classes.
Now, looking at the code you provided, the following compiler errors pop up:
FooType.FeeType1': cannot declare instance members in a static class
This error means that if the class is declared static, all of the members must be static too.
FooType.FeeType1' is a 'property' but is used like a 'type'
This arises from the fact that the class is static but none of the members are.
Inconsistent accessibility: parameter type 'FooType.FeeType' is less
accessible than method 'IWebApp.RouteOneBuilder(FooType.FeeType)'
The return type and each of the types referenced in the formal parameter list of a method must be at least as accessible as the method itself.
You can find more information about the last error here.
The design is not correct.
If a type is marked as internal this indicates that it should never be accessed outside of its DLL. If this type must be accessed outside of the DLL in which it is declared, it should not be marked internal.
What constraint is preventing you from using a public modifier or from including the types in the same DLL as the consuming code?
In certain cases it is useful for external DLLs or EXEs to view internal members declared in another DLL. One notable case is for unit testing. The code under test may have an internal access modifier, but your test DLL still needs to access the code in order to test it. You can add the following to AssemblyInfo.cs of the project containing the internal members to allow external access.
[assembly:InternalsVisibleTo("Friend1a")]
See InternalsVisibleToAttribute Class for more details.
Side note: The sealed access modifier doesn't prevent access from outside of the declaring DLL. It prevents other types from extending the type.
Imagine the following scenario in a Xamarin solution:
Assembly A (PCL):
public abstract class MyBaseClass
{
public MyBaseClass()
{
[...]
}
[...]
}
Assembly B (3rd Party Library):
public class SomeLibClass
{
[...]
public void MethodThatCreatesClass(Type classType){
[...]
//I want to allow this to work
var obj = Activator.CreateInstance(classType);
[...]
}
[...]
}
Assembly C (Main project):
public class ClassImplA:MyBaseClass{
[...]
}
public class ClassImplA:MyBaseClass{
[...]
}
public class TheProblem{
public void AnExample(){
[...]
//I want to block these instantiations for this Assembly and any other with subclasses of MyBaseClass
var obj1 = new ClassImplA()
var obj2 = new ClassImplB()
[...]
}
}
How can I prevent the subclasses from being instantiated on their own assembly and allow them only on the super class and the 3rd Party Library (using Activator.CreateInstance)?
Attempt 1
I though I could make the base class with an internal constructor but then, I saw how silly that was because the subclasses wouldn't be able to inherit the constructor and so they wouldn't be able to inherit from the superclass.
Attempt 2
I tried using Assembly.GetCallingAssembly on the base class, but that is not available on PCL projects. The solution I found was to call it through reflection but it also didn't work since the result of that on the base class would be the Assembly C for both cases (and I think that's because who calls the constructor of MyBaseClass is indeed the default constructors of ClassImplA and ClassImplB for both cases).
Any other idea of how to do this? Or am I missing something here?
Update
The idea is to have the the PCL assembly abstract the main project (and some other projects) from offline synchronization.
Given that, my PCL uses its own DB for caching and what I want is to provide only a single instance for each record of the DB (so that when a property changes, all assigned variables will have that value and I can ensure that since no one on the main project will be able to create those classes and they will be provided to the variables by a manager class which will handle the single instantions).
Since I'm using SQLite-net for that and since it requires each instance to have an empty constructor, I need a way to only allow the SQLite and the PCL assemblies to create those subclasses declared on the main project(s) assembly(ies)
Update 2
I have no problem if the solution to this can be bypassed with Reflection because my main focus is to prevent people of doing new ClassImplA on the main project by simple mistake. However if possible I would like to have that so that stuff like JsonConvert.DeserializeObject<ClassImplA> would in fact fail with an exception.
I may be wrong but none of the access modifiers will allow you to express such constraints - they restrict what other entities can see, but once they see it, they can use it.
You may try to use StackTrace class inside the base class's constructor to check who is calling it:
public class Base
{
public Base()
{
Console.WriteLine(
new StackTrace()
.GetFrame(1)
.GetMethod()
.DeclaringType
.Assembly
.FullName);
}
}
public class Derived : Base
{
public Derived() { }
}
With a bit of special cases handling it will probably work with Activator class , but isn't the best solution for obvious reasons (reflection, error-prone string/assembly handling).
Or you may use some dependency that is required to do anything of substance, and that dependency can only be provided by your main assembly:
public interface ICritical
{
// Required to do any real job
IntPtr CriticalHandle { get; }
}
public class Base
{
public Base(ICritical critical)
{
if (!(critical is MyOnlyTrueImplementation))
throw ...
}
}
public class Derived : Base
{
// They can't have a constructor without ICritical and you can check that you are getting you own ICritical implementation.
public Derived(ICritical critical) : base(critical)
{ }
}
Well, other assemblies may provide their implementations of ICritical, but yours is the only one that will do any good.
Don't try to prevent entity creation - make it impossible to use entities created in improper way.
Assuming that you can control all classes that produce and consume such entities, you can make sure that only properly created entities can be used.
It can be a primitive entity tracking mechanism, or even some dynamic proxy wrapping
public class Context : IDisposable
{
private HashSet<Object> _entities;
public TEntity Create<TEntity>()
{
var entity = ThirdPartyLib.Create(typeof(TEntity));
_entities.Add(entity);
return entity;
}
public void Save<TEntity>(TEntity entity)
{
if (!_entities.Contains(entity))
throw new InvalidOperationException();
...;
}
}
It won't help to prevent all errors, but any attempt to persist "illegal" entities will blow up in the face, clearly indicating that one is doing something wrong.
Just document it as a system particularity and leave it as it is.
One can't always create a non-leaky abstraction (actually one basically never can). And in this case it seems that solving this problem is either nontrivial, or bad for performance, or both at the same time.
So instead of brooding on those issues, we can just document that all entities should be created through the special classes. Directly instantiated objects are not guaranteed to work correctly with the rest of the system.
It may look bad, but take, for example, Entity Framework with its gotchas in Lazy-Loading, proxy objects, detached entities and so on. And that is a well-known mature library.
I don't argue that you shouldn't try something better, but that is still an option you can always resort to.
I am working on a class Library and I'm having troubles with accessibility. My class library contains several internal classes which shouldn't be accessed from other applications. Instead I want to create a Singleton Main Class that contains Instances of all the internal classes, so other applications can access the Main class and then use the internal classes from that instance. The picture below explains the hierarchy.
I've tried making the Main Class public and the Internal Classes internal, however this gives me the error Error "Inconsistent accessibility". My Main Class looks like this:
public class Main
{
private static Main Instance;
public static Main GetInstance()
{
if (Instance == null)
Instance = new Main();
return Instance;
}
public Debugging Debugger = new Debugging();
}
And one of my Internal Classes (Debugging) looks like this:
internal class Debugging
{
Content....
}
So I'm hoping that someone can help me to figure out how to make the Internal Classes only accessible through my singleton Main Class.
I'm not positive from your question what your intent is so I'll break it into two options:
You want `Debugging` accessible to external assemblies, but only via `Main`
There are a few ways how to do this, but the simplest right now for you would be to keep Debugging public, but define only internal constructors. This will allow its usage but external assemblies won't be able to instantiate them, thus forcing them to access the instance created on Main
public class Debugging
{
internal Debugging() { }
}
You don't want `Debugging` accessible to external assemblies, and but still accessible within your class assembly via `Main`
Simply update the accessibility modifier for Main.Debugger to be internal
internal Debugging Debugger = new Debugging();
You have to set all of you class public if you have some public access to them (via the Main class).
Otherwise you can set the internal class as internal and provide a set of properties in the Main class (that wrap internal classes' fields/methods) in order to access their field/methods. You can set the constructors of internal class as internal in order to avoid those class instantiations.
In general: Every field/method exposed from a public class should have a public return type.
Some MSDN reference
If you need to access the Debugger class outside the Library you need to change the access modeifier to public. As suggested make the constructor as internal so no one outside the assembly can create an instance of those classes.
I have a web service in C# and would like to have a nested inner class, that abstracts away the session collection, something like this:
public class Service : System.Web.Services.WebService
{
[WebMethod]
public string Foo(string ticket)
{
SessionPool.getSession(ticket);
}
private class SessionPool
{
public static Session getSession(string ticket)
{
// this is what i want to do, but I can't access Context
return (Session)Context.Session[ticket];
}
}
}
Is it possible to access the HTTP context of the WebService class via a nested class? If not, is there way I can store the reference to it?
Nested classes in C# aren't like (non-static) inner classes in Java. There is no implicit reference to an instance of the containing class - so you can't use any instance members of the containing class without an explicit reference.
However, you do have access to all private members of the containing class - with a suitable reference for instance members.
System.Web.HttpContext.Current
?
I can think of a couple things.
First, you might try using getContext() instead of just accessing Context. If that works, you're done.
If not, you could pass the Service in as an initializer to your SessionPool. Add a WebService handle to SessionPool that you initialize via a call to setService() before calling getSession() from Foo().
Although, at that point, why not just pass in the Context as an argument to getSession()?