Reputation: 6356
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?
Upvotes: 0
Views: 2994
Reputation: 4996
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.
Upvotes: 0
Reputation: 137188
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.
Upvotes: 0
Reputation: 83014
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.
Upvotes: 9
Reputation: 74842
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.
Upvotes: 5
Reputation: 191058
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 ...
}
Upvotes: 2