Partially encapsulate a field C# - c#

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 :)

Related

Subclassing and generics in C#

I want to subclass a large number of classes so that they will all contain a certain set of the same properties. What would be the right way to do it in order to avoid repetition? I thought of using generics like:
public class SuperT<T> : T
{
//the same set of properties
}
But the compiler says
Cannot derive from 'T' because it is a type parameter
EDIT: I am trying to subclass some classes in a third party assembly so I cannot use a base class.
For example, the types are "Image", "Label", "Button" etc and I want to subclass them all to contain a property like "Radius". (So that I would use SuperImage element in XAML and when I set it's Radius property from XAML, I will be able to run some certain logic.)
One other way I just thought of right now is using T4 templates. I wonder if there is a way to do this with generics without resorting to templates? I cannot understand why the compiler rejects it.
If these classes all share a common base class or common interface you could write an extension method.
public static class ShapeExetnsionsExtLib
{
public static double Radius(this ShapeBase shape){
return /*calculate radious*/;
}
}
From comments
I am trying to subclass some classes in a third party assembly so I cannot use a base class.
For example, the the types are "Image", "Label", "Button" etc and I want to subclass them all to contain a property like "radius".
Yes they share common base classes but I cannot add anything new to them.
I don't think generics have anything to do with this, however inheritance is probably what you're looking for.
There are two types of inheritance that you can use to subclass, and extension methods work to "superclass"... sort of.
Is-A inheritance
Has-A inheritance
And to simply add a similar method to a bunch of third party objects, you'll use an extension method.
Is-A inheritance
Use a base class if you've got similar method implementations.
public abstract class BaseFoo {
public void Bar() {
// actual code
}
}
public class Foo : BaseFoo
{
}
var foo = new Foo();
foo.Bar();
Use an Interface if you need to implement the same method on each class.
public interface IFoo {
void Bar();
}
public class Foo : IFoo {
public override void Bar(){
// bar implementation
}
}
var foo = new Foo();
foo.Bar();
Combining the two is also allowed, but you can only inherit on base class, where you can inherit multiple interfaces.
Has-A inheritance
This is particularly useful with dependency injection, but it's simply the notion that you have an instance of another class to work with. It's essentially a wrapper class for you to work with.
public class Foo {
private readonly ThirdPartyFoo _tpFoo;
void Foo(ThirdPartyFoo tpFoo) {
_tpFoo = tpFoo;
}
public void Bar(){
// now I can do something with _tpFoo;
_tpFoo.Bar();
}
}
var tpFoo = new ThirdPartyFoo();
var foo = new Foo(tpFoo);
foo.Bar(); // invokes the underlying tpFoo
Lastly, if you just need to add a method to existing classes, then you create an extension method.
public static class ViewExtensions()
{
// this assumes your Image, Button, Label all inherit from View.
public static Whatever Radius(this View view) {
// do your radius work.
}
}
Just Use a base class:
public class Base
{
public int Id { get; set; }
public string Name { get; set; }
}
And inherite from it:
public class A : Base
{
}
public class B : Base
{
}
In general, you want to use one of the answers already posted about using a base class and inheriting from that. However, if the classes are in a third party library and are marked as sealed, then you will need to create a wrapper class to use as a base class.
(Note that this option is a workaround and doesn't truly inherit from the third party class, so things in that class that are marked as protected won't be accessible without a liberal use of reflection.)
// The sealed class within another library
public sealed ThirdPartyClass
{
public ThirdPartyClass(int i) { }
public int SomeProperty { get; set; }
public int SomeMethod(string val) { return 0; }
public static void SomeStaticMethod() { }
}
// The wrapper class to use as a pseudo base class for ThirdPartyClass
public class BaseClass
{
private ThirdPartyClass _obj;
public BaseClass(int i) { _obj = new ThirdPartyClass(i); }
public int SomeProperty
{
get { return _obj.SomeProperty; }
set { _obj.SomeProperty = value; }
}
public int SomeMethod(string val) { return _obj.SomeMethod(val); }
public static SomeStaticMethod() { ThirdPartyClass.SomeStaticMethod(); }
}
// The child class that inherits from the "base" BaseClass
public class ChildClass : BaseClass
{
}
First of all, this might be a logical problem. What if you are going to extend a sealed class? Or Int32 class? Delegate?
Anyway, the way I recommend is to create an interface and implement all the functions you need in the subclass.

Is it possible to limit instances of public inner enum or class to its parent class in C#?

I would like to define an enum inside of a class. The class will have a public property of the enum type. I would like classes outside this class to be able to reference this class' enum property, but I don't want other classes to be able to create their own instances of this enum. Is this even possible? Consider this example:
public class MyClassWithEnum
{
public Season MySeason { get; set; }
public enum Season { Winter, Spring, Summer, Fall }
}
public class OutsideClass
{
public void OutsideClassMethod()
{
MyClassWithEnum enumClass = new MyClassWithEnum();
enumClass.MySeason = MyClassWithEnum.Season.Spring; // This should be okay
MyClassWithEnum.Season localSeason = MyClassWithEnum.Season.Winter; // This should NOT be okay
}
}
It seems to me I am left to choose between defining the enum as public and letting any other class create instances of it, or making it private and not being able to set it from outside the class.
You do not instantiate Enums as if it where classes, therefore you cannot prevent someone to use it. With a class you could have a private ctor for example... That's obviously not possible with Enums.
So yes, your assumption is correct, either make it internal or private, or make it public... ;)
Btw, I cannot think about any good scenario where you want to hide the Enum while having a public property using the Enum, even if it where possible to do this.

Adding a data member to an already existing class in C#

I was reading about extension methods and how they can extend classes with new methods without having to change the class code definition.
I wanted to know if there was any similar way by which I can add a new data member (like a List or an array) to an existing class and use the data member to store information related to the class?
Yes you can extend that class using inheritence.
public class MyClass
{
...
}
public ExtendedClass: MyClass
{
public int ExtraField {get; set;}
}
This way you have all of the members and methods (except private) that exist on the base.
With extension methods you can only extend the functionality of a class.
What you are looking for can be solved with:
Aggregation OR
Inheritance
This post may help you on deciding which one to use in your case: Inheritance vs. Aggregation
There is no way of directly adding members to a specific class.
If the class isn't sealed, you may extend that class by using inheritance. If it is sealed, you may compose yourself a new class which encapsulates the specific class you wanted to extend and extend the implementation.
For example, if you have MyClass which isn't sealed and you want to extend it, simply inherit:
public class MyExtendedClass : MyClass
{
// Add extra logic
}
or, as for composing a new class yourself, you may do the following:
public class MyExtendedClass
{
private MyClass _class;
public string MyExtraString { get; set; }
}
You can use inheritance or composition for that.
Inheritance Example:
public class Student
{
int age;// all props
}
public class MAStudent : Student // MSStudent is a student with extra stuff.
{
float maAverage;
}
Composition Example:
public class Student
{
int age;// all props
}
public class MAStudent
{
Student student;
float maAverage;
// use student's functions inside the class
}
Inheritance is the easiest way to do things. The problem with it is that it makes your classes coupled.
The good perk with inheritance that you can access every protected+ property \ method.
Although the other answers seem to be correct, the answer to your question IMHO, is that it is not possible to extend an existing class with new properties in the way that extension methods do that. Once a class is defined, you cannot 'add' things to it.
Extension method is an exception, since that is just syntactic sugar for a static helper class.
Also you can write something based on extension methods like this
public class ExistingClass
{
}
public static class ExtendingExistingClass
{
private static Dictionary<ExistingClass,List> _values = new Dictionary<ExistingClass,List>();
public List GetMyNewField(this ExistingClass t)
{
List res = null;
_values.TryGetValue(t, out res);
return res;
}
public void SetMyNewField(this ExistingClass t, List value)
{
_values[t] = value;
}
}

How Can an Attribute Class Reference the Instance that Uses It?

Let's say I have an attribute class:
public class MyCustomAttribute : Attribute
{
// do stuff
}
And I use this attribute on class properties:
public class MyModel : BaseModel
{
[MyCustom]
public string Name { get; set; }
}
Is there a way, within the code of MyCustomAttribute, to reference the instance of MyModel on which it's being used?
Ultimately I'm just experimenting with AOP (using PostSharp) to create attributes to track when a model is dirty. So if BaseModel has an IsDirty property then I'd like to be able to do something like this with PostSharp:
public class TrackDirtyPropertyAttribute : OnMethodBoundaryAspect
{
public override void OnSuccess(MethodExecutionArgs args)
{
someReferenceToTheObject.IsDirty = true;
}
}
I've tried passing a reference into the attribute's constructor:
public class TrackDirtyPropertyAttribute : OnMethodBoundaryAspect
{
private BaseModel _currentObject { get; set; }
public TrackDirtyPropertyAttribute(BaseModel currentObject)
{
_currentObject = currentObject;
}
public override void OnSuccess(MethodExecutionArgs args)
{
_currentObject.IsDirty = true;
}
}
However, when I use it:
[TrackDirtyProperty(this)]
public string Name { get; set; }
It tells me that this is not available in that context.
You should do it like this:
public class TrackDirtyPropertyAttribute : OnMethodBoundaryAspect
{
public override void OnSuccess(MethodExecutionArgs args)
{
((BaseModel) args.Instance).IsDirty = true;
}
}
Your constructor won't work (at least not with this) because the attribute constructor arguments must be accessible in a static context. And by default you can't simply access the utilising type's instance - which makes sense, since this is essentially metadata (applied to the definition, not instances - the instances just come 'strapped' with it). So you can natively access the attributes of a type, but not the instances of the type used by an attribute.
You could probably get it through some contrived reflection and so forth (I'm not even going to venture into thinking about this), however, not so elegantly one way as the other.
On another note, it makes little sense to me to store the state of an element within an attribute - this isn't persistent enough. Making calculations to retrieve a value (say you did get a hold of the instance, and managed to run some logic to determine if it 'is dirty' and provide a 'real time' value in that sense) yes, but using it to persist information applied to it after the fact of declaration seems futile, since which instance of the attribute is it to persist in anyway? In any case, and regardless of what I might have totally missed in saying this, this is what the instances themselves are for.

Using partial classes to add private properties?

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.

Categories