I have a public class I'm defining that will eventually be part of an API, so it has to have certain public properties. However, I also want some of the properties to be read-only unless they're created from within my own projects (e.g., if a user has our API, they can create a User object, but they can't write to its ID field, which will be filled in only if we pull it from the database).
My thought was to have two separate assemblies using the same namespace, the "public" DLL and the "private" DLL. The prototype in the public DLL will look like:
namespace CompanyName
{
public partial class User
{
public Id { get; }
public Name { get; set; }
}
}
and the private DLL will have this:
namespace CompanyName
{
public partial class User
{
public Id { set; }
}
}
Would this work? If not, what's a better way to do this?
Partial classes cannot span assemblies, so this will not work.
You could define your class as:
namespace CompanyName
{
public class User
{
public Id {get;internal set;}
public Name {get;set;}
}
}
This would mean that only code with internal access to your class could set the value of Id property. If you need to set it from outside your assembly, make sure your assemblies are strong-named and you can then use the InternalsVisibleTo attribute to give internal access to your assembly to another one of your assemblies (the one setting the value of Id).
I've recently had to do something very similar to this for an API I work on. Our API is defined mainly using interfaces, so I was able to achieve this by having a Public API project that is the public part, and an Internal API project that forms the API used by our internal code, with internal interfaces deriving from the public ones. The implementations of the API interfaces implement both interfaces, meaning our internal code can then access parts of the API that are not public.
No, this wouldn't work. Partial classes are merged at compile time: you can't add members to a compiled class.
Depending on exactly how your code is laid out, a better approach is to provide an internal setter:
public int Id { get; internal set; }
If you need to be able to do the set from another assembly, but only one you control, you can use InternalsVisibleToAttribute to grant that assembly access to the internal setter.
I doubt this would work. I would imagine partial classes are compiled together into the same assembly and not handled by the CLR. You might want to see the internal keyword.
Maybe do something like this
abstract internal class UserPrototype
{
protected Property....
}
sealed class User : UserPrototype
{
public ...
}
Even if you could do this, your private properties and fields will still be discoverable via reflection. From the MSDN page for GetProperty:
The following BindingFlags filter flags can be used to define which properties to include in the search:
You must specify either BindingFlags.Instance or BindingFlags.Static in order to get a return.
Specify BindingFlags.Public to include public properties in the search.
Specify BindingFlags.NonPublic to include non-public properties (that is, private and protected properties) in the search.
The trick with designing APIs is to think in categories of interfaces (int this case - abstract classes). Please have a look at this code:
public abstract class User
{
protected String _name;
}
public sealed class PublicUser : User
{
public String Name
{
get{ return this._name; }
}
}
public class PrivateUser : User
{
public String Name
{
get { return this._name; }
set { this._name = value; }
}
}
Obviously you can use any class/namespace names, this is just for making things clear. All classes are - as you can see - public, so it's up to you now which DLL will be available for your client.
Related
I am trying on a project to use private values in my internal functions. In past I used only public ones, but I noticed that obfuscation is working much better when using as much as possible private parameters.
My question is regarding Parent/Child classes.
In my main class I define all the parameters as following :
public class MyFatherClass
{
private long id = -1;
public long ID { get { return this.id; } set { this.id = value; } }
...
}
So in all internal functions I access to my private value instead of the public one.
Then in my daughter class I just add parameters specific to the child class.
public class MyChildClass : MyFatherClass
{
private long anotherParameter = -1;
public long AnotherParameter { get { return this.anotherParameter; } set { this.anotherParameter = value; } }
...
}
Just, I see that in my Parent class, I can access to id and ID without problem, but from daughter classes I can only access ID(as id is private).
If I understood correct, I would need to replace all private by protected in my parent lass, so it would solve the problem?
What I don't understand is the code is working even if I leave it so.
Why don't I have an error message, when I set ID value in daughter class, the sentence this.id=value is executed, but how can can I access to it from my child class if it is private?
I am now hesitating, may I just add a private id in each child class, or may I set id to protected in my parent class?
Thanks for your explanations.
Edit, just adding a screenshot of my reversed code after obfuscation, so you could understand difference on how are obfuscated private/public methods/fields
Why don't I have an error message, when I set ID value in daughter class, the sentence this.id=value is executed, but how can can I access to it from my child class if it is private?
When you call a public method on a class, that method can access private members of that class:
public class Foo
{
public void Bar()
{
Baz();
}
private void Baz()
{
// private method called by public method
}
}
var foo = new Foo();
foo.Bar();
This compiles just fine. Your setter is the same: it's public, so callable from everywhere, even if it accesses private members.
As for making your field (private long id = -1;) protected: yes, that will mean you can access it in derived classes. But whether you want to is another question.
You have declared a public property for a reason. Perhaps you want to do some validation in its setter or getter. If not, if you're just using a property to access a private field, you could just ditch the entire private field and use an auto-implemented property:
public long ID { get; set; } = -1;
Then you can access the property everywhere, from within itself, from derived classes and from code using this class.
See also:
What is the difference between a field and a property?
What are Automatic Properties in C# and what is their purpose?
Here is a short and reduced description of what access modifiers do:
Public : fields (variables) and properties (variables encapsulation) and methods (functions and procedures) are visible and accessible by the class itslef, by its childs and by any other external classes.
Private : members (fields, properties and methods) are visible and accessible only by the class, not by its childs nor by any external class.
Protected : members are visible and accessible by the class and by its childs, but not by others classes.
Internal : members are visible and accessible by the class and by its childs and by any class that is in the same assembly (.exe and .dll), but not by a class from another assembly.
So you should set id to protected in the parent class to use it in the childs.
But here is the rule:
If childs classes can modify id you should set as a protected field, and offer a public property (get) if available for external items.
If childs classes are not allowed to modify it you should set it private and offer :
A propected property with only a getter if external items can't access it.
A public property with only a getter if external items can access it.
Don't repeat a member with the same name else it will hide the parent and can cause polymorphism problems, else you know what you do.
You can read these tutorials to more understand access modifier keywords:
C# Access Modifiers
Access Modifiers (C# Reference)
Here are some readings:
C# Tutorial Level 0
C# Tutorial Level 1
C# Tutorial Level 2
C# Tutorial Level 3
C# Snippets # Techi.io
Beginning Visual C# 2008 Programming
The MyChildClass class which inherits from the MyFatherClass can not access the id field because it's private. To make it accessible, you will need to change the field's access modifier to either:
protected :
////////////////////////////////////
// Dll1.dll
////////////////////////////////////
namespace Dll1
{
public class Base
{
//The field we are attempting to access
protected int a;
}
public sealed class Main : Base
{
public void DoSomething()
{
//Can be done sins Main inherits from Base
base.a = 100;
}
}
public class Invader
{
public int GetA()
{
var main = new Main();
main.DoSomething();
// can not be done sins the field is only accessible by those that inherit from Base
return main.a;
}
}
}
////////////////////////////////////
// Dll2.dll
////////////////////////////////////
namespace Dll2
{
public class ADll2Class : Dll1.Base
{
public int GetA()
{
//Can be done because ADll2Class inherits from Dll1's Base class
return base.a;
}
}
}
private protected :
Same as protected but, in the example above, Dll2's class, ADll2Class, will not be able to access the a field because it would be privately protected, in other words only classes from the same dll as Base which inherit from Base will be able to access a.
or you can set it to
internal :
If the a field in the example above was internal, then, same as private protected, Dll2's class wont be able to access it but, the Invader class in Dll1 will be able to access it sins it's part of the same dll as Base.
Note that, sins you mentioned obfuscation, try as hard as you will, the id field can still be accessed by others in an obfuscated state with the help of reflection, especially sins you provide a public property ID, might as well set everything in your project to internal.
I'm going through a really hard time finding the answer to the question below, about inheritance and OOP. Can anyone please help?
Here is the question :
Let's assume that I have a class named ServiceManager inside an assembly named KioskFramework, which implements 2 different interfaces named IServiceManager and IServiceProvider.
public interface IServiceManager
{
string SerialNumber { get; }
string Description { get; set; }
int DoFoo(IServiceManager instance, int a, int b);
}
public interface IServiceProvider
{
void DoSomethingRESTRICTED();
}
class ServiceManager : IServiceManager, IServiceProvider
{
public void DoSomethingRESTRICTED();
… // some other properties and methods...
public string SerialNumber { get { … } }
public string Description { get { … } set { … } }
public int DoFoo(int a, int b)
{
…
}
}
I have another class named MonitoringService inside an assembly named KioskFramework.MonitoringService, which uses certain properties of ServiceManager class (The ones that are defined in the IServiceManager).
class MonitoringService
{
… // some other properties and methods...
public int DoBar(IServiceManager instance, int a, int b)
{
// an example to show that I need access to ServiceManager's properties
return instance.SerialNumber.Length +
instance.Description.Length +
instance.DooFoo(a, b);
}
}
All I want to do is, that I want to be able to use that certain properties in MonitoringService, but no other class or assembly (such as ControllingService inside KioskFramework.ControllingService), could access that properties.
class ControllingService
{
public void DoSomethingElse(IServiceProvider instance)
{
// this method should not have access to the IServiceManager's
// properties and methods, even if it has an instance of
// IServiceProvider, or even if it has referenced the assembly
// containing IServiceManager interface
}
}
Is it possible? How? Is there a design pattern for solving this?
Maybe I'm thinking in a wrong manner or way, but my goal is to restrict certain members of a class to only be seen/used in certain assemblies not all of them.
edit : After Mark Cidade's answer, I edited this post, to say that I don't want to expose other internal members and classes of "KioskFramework" assembly to "KioskFramework.MonitoringService" assembly.
Thanks in advance.
You can mark the interface as internal and apply an InternalsVisibleTo attribute to the assembly:
From KioskFramework.dll:
[assembly:InternalsVisibleTo("KioskFramework.MonitoringService")]
I am not sure what your goal is - so some general pointers:
you can make those interfaces internal and define which assembly is allowed to see those members assembly: InternalsVisibleTo
you can make the members protected and access them via Reflection
I currently have a solution with multiple projects that mostly use the same classes. As a result, it appeared to me that it would be a good idea to add a class library containing these classes in the solution instead of repeating the class in each project.
However, one project I have requires a few additional properties to some of the classes that are specific to that project and will not be used anywhere else. As a result, I thought that I should use partial classes to add these properties. So I have done something like this:
In the class library:
namespace MyClassLibrary
{
public partial class Book
{
public string Title { get; set; }
public string AuthorLast { get; set; }
public string AuthorFirst { get; set; }
public string Publisher { get; set; }
public string Edition { get; set; }
public string ISBN10 { get; set; }
public string ISBN13 { get; set; }
}
}
In the project (MyProject):
namespace MyClassLibrary
{
public partial class Book
{
public string AdditionalProperty { get; set; }
}
}
I have referenced MyClassLibrary in MyProject (a C# windows form app), however when I try to use this class in the codebehind for the form I receive the following error:
class MyClassLibrary.Book
Warning: The type
'MyClassLibrary.Book' in 'C:...
(Project)' conflicts with the imported
type 'MyClassLibrary.Book' in 'C:...
(Class Library DLL)'. Using the type
defined in 'C:...(project)'.
Any idea what I am doing wrong or if my whole approach is bad and I should be doing something else?
Partials are not for spanning assemblies. If you need to add to your class for a more specific type of usage, you should create a derived class:
public class MyFoo
{
public string BasicProperty {get;set;}
}
public class MySpecificFoo : MyFoo
{
public string AnotherProperty {get;set;}
}
In your project requiring the more specific type of MyFoo, utilize MySpecificFoo instead. Since it inherits/derives from MyFoo, it will have all of the properties and functionality of MyFoo, with the additional properties as well. This is part of Polymorphism, which is where real power of OOP lies.
In short, you can't use partial classes across projects. All the source must be compiled at the same time, and that's done per project.
Here's a full discussion on SO about this: Should you use a partial class across projects?
For what you're trying to do, you should instead try to use base classes and inheritance. Or even better object composition.
I think this is more along the lines of what you're trying to achieve.
Put all of your common classes into a class library project and compile it to a DLL.
You can then reference that DLL in external projects. Anytime you need to add a property to it for the external project you can then inherit the class and add the property there.
all wrong. You should consider partial methods instead. Look 'em up. They're exactly what you asked for.
I want to know if there is any pattern that can overcome this problem:
I have a set of properties that needed to be public to several classes and to other classes they should be only readonly,
the classes must be public.
I do not want to use reflection or any other bad performance makers.
I know I can make them RO and implement logic inside class but I don't think it's good.
Any help?
Inside the current assembly, you can make it internal.
Outside the current assembly, the best you can do is make it available to specific assemblies, via [InternalsVisibleTo].
.NET does not offer more granular "friend" access.
class Person : IReadOnlyPerson {
public string Name { get; set; }
}
public interface IReadOnlyPerson {
string Name { get; }
}
To those classes that should do r/o access - use IReadOlyPerson
Two options:
Make the property internal (not the class) and group the classes into different assemblies.
Use reflection magic.
Sadly, there are no friend classes in C#.
You could try declaring your setters as protected in your base class. Any class that derives it will be able to set it. But any class using the derived class will only see a read-only property.
public class ClassBase
{
public int MyProperty
{
get;
protected set;
}
}
public sealed class ClassDerived : ClassBase
{
public ClassDerived()
{
MyProperty = 4; // will set
}
}
public class ClassUsingDerived
{
public ClassUsingDerived()
{
ClassDerived drv = new ClassDerived();
drv.MyProperty = 5; // will fail
}
}
That is if i understand the question correctly :)
Suppose I have a class 'Application'. In order to be initialised it takes certain settings in the constructor. Let's also assume that the number of settings is so many that it's compelling to place them in a class of their own.
Compare the following two implementations of this scenario.
Implementation 1:
class Application
{
Application(ApplicationSettings settings)
{
//Do initialisation here
}
}
class ApplicationSettings
{
//Settings related methods and properties here
}
Implementation 2:
class Application
{
Application(Application.Settings settings)
{
//Do initialisation here
}
class Settings
{
//Settings related methods and properties here
}
}
To me, the second approach is very much preferable. It is more readable because it strongly emphasises the relation between the two classes. When I write code to instantiate Application class anywhere, the second approach is going to look prettier.
Now just imagine the Settings class itself in turn had some similarly "related" class and that class in turn did so too. Go only three such levels and the class naming gets out out of hand in the 'non-nested' case. If you nest, however, things still stay elegant.
Despite the above, I've read people saying on StackOverflow that nested classes are justified only if they're not visible to the outside world; that is if they are used only for the internal implementation of the containing class. The commonly cited objection is bloating the size of containing class's source file, but partial classes is the perfect solution for that problem.
My question is, why are we wary of the "publicly exposed" use of nested classes? Are there any other arguments against such use?
I think it's fine. This is basically the builder pattern, and using nested classes works pretty well. It also lets the builder access private members of the outer class, which can be very useful. For instance, you can have a Build method on the builder which calls a private constructor on the outer class which takes an instance of the builder:
public class Outer
{
private Outer(Builder builder)
{
// Copy stuff
}
public class Builder
{
public Outer Build()
{
return new Outer(this);
}
}
}
That ensures that the only way of building an instance of the outer class is via the builder.
I use a pattern very much like this in my C# port of Protocol Buffers.
You can use namespaces to relate things that are... related.
For example:
namespace Diner
{
public class Sandwich
{
public Sandwich(Filling filling) { }
}
public class Filling { }
}
The advantage of this over using classes as if they were namespaces is that you can optionally use using on the calling side to abbreviate things:
using Diner;
...
var sandwich = new Sandwich(new Filling());
If you use the Sandwich class as if it were a namespace for Filling, you have to use the full name Sandwich.Filling to refer to Filling.
And how are you going to sleep at night knowing that?
You might want to check out what Microsoft has to say on the topic. Basically it's a question of style I'd say.
Another practical example that I have for a valid use of public nested classes is in MVC pattern when I use a viewmodel with an IEnumerable property. for example:
public class OrderViewModel
{
public int OrderId{ get; set; }
public IEnumerable<Product> Products{ get; set; }
public class Product {
public string ProductName{ get; set; }
public decimal ProductPrice{ get; set; }
}
}
I use it because I don't want Product class to be re-used outside because it is customized only for that specific viewmodel which contains it. But I can't make it private because the Products property is public.
I primarily use nested classes for fine-tuning access to the nested and/or the container class.
One thing to remember is that a nested class definition is basically a class member, and will have access to all the container's private variables.
You can also use this to control usage of a specific class.
Example:
public abstract class Outer
{
protected class Inner
{
}
}
Now, in this case, the user (of your class) can only access the Inner class, if he implements Outer.
I don't know if this is considered bad design or not, but I've got some search classes I make where a user calls the Run() method, passing in an object that holds search criteria. It then returns a collection of search result objects.
These SearchCriteria and SearchResult classes have no utility outside of using them with the Search class. So I nest them under the Search class to show they go together.
I have to make the nested classes public so the client of the Search class can make the SearchCriteria to pass into the Search class and so they can get the results of the Search.
public class PersonSearch
{
public PersonSearchCriteria
{
string FirstName {get; set;}
string LastName {get; set;}
}
public PersonSearchResult
{
string FirstName {get;}
string MiddleName {get;}
string LastName {get;}
string Quest {get;}
string FavoriteColor {get;}
}
public static List<PersonSearchResult> Run(PersonSearchCriteria criteria)
{
// create a query using the given criteria
// run the query
// return the results
}
}
public class PersonSearchTester
{
public void Test()
{
PersonSearch.PersonSearchCriteria criteria = new PersonSearch.PersonSearchCriteria();
criteria.FirstName = "George";
criteria.LastName = "Washington";
List<PersonSearch.PersonSearchResults> results =
PersonSearch.Run(criteria);
}
}