I'm trying to figure out what the proper syntax is to achieve a certain API goal, however I am struggling with visibility.
I want to be able to access a Messenger instance's member like msgr.Title.ForSuccesses.
However, I do not want to be able to instantiate Messenger.Titles from outside my Messenger class.
I'm also open to making Messenger.Titles a struct.
I'm guessing I need some sort of factory pattern or something, but I really have no idea how I'd go about doing that.
See below:
class Program {
static void Main(string[] args) {
var m = new Messenger { Title = { ForErrors = "An unexpected error occurred ..." } }; // this should be allowed
var t = new Messenger.Titles(); // this should NOT be allowed
}
}
public class Messenger {
// I've tried making this private/protected/internal...
public class Titles {
public string ForSuccesses { get; set; }
public string ForNotifications { get; set; }
public string ForWarnings { get; set; }
public string ForErrors { get; set; }
// I've tried making this private/protected/internal as well...
public Titles() {}
}
public Titles Title { get; private set; }
public Messenger() {
Title = new Titles();
}
}
You just need to make Titles private and expose an interface instead of it.
class Program {
static void Main(string[] args) {
var m = new Messenger { Title = { ForErrors = "An unexpected error occurred ..." } }; // this is allowed
var t = new Messenger.Titles(); // this is NOT allowed
}
}
public class Messenger {
public interface ITitles {
string ForSuccesses { get; set; }
string ForNotifications { get; set; }
string ForWarnings { get; set; }
string ForErrors { get; set; }
}
private class Titles : ITitles {
public string ForSuccesses { get; set; }
public string ForNotifications { get; set; }
public string ForWarnings { get; set; }
public string ForErrors { get; set; }
}
public ITitles Title { get; private set; }
public Messenger() {
Title = new Titles();
}
}
If you make the Titles constructor internal you will be able to create instances of it within your assembly only. If it is an API, perhaps that will be protected enough? You can see this pattern within the BCL (such as HttpWebRequest that can be created only through calls to WebRequest.Create).
Why Would I Ever Need to Use C# Nested Classes Nested type is never intended to be initialized from external type.
Well, you could make Titles a struct and make the constructor either public or internal. In that way, every time a client gets a copy of the Titles instance through the Title property, they will be getting the value, not the reference. They could modify that value, but to apply that change to the internal state of your object, they would need to be able to set the value back again through the Title property. They can't, because you have the Title setter marked private.
You will have to do the same when you change a value internally. For example:
// Your constructor...
public Messenger()
{
Titles t = new Titles();
t.ForSuccesses = "blah";
Title = t;
}
You can do this internally because you have access to the private setter for the Title property.
The main downside is that it might confuse the clients of your framework a bit because it looks like you can set the values of the Titles instance, but there is no real way for them to commit that change back to the Messenger class.
Related
I have a method as follows which gets data and stores them to specific variables. I also have two static variables that preserves their value if a condition is met. My question is how can I store this data in attributes in a specific class ?
Like for example, I have a class called UserDetails with attributes :
UserDetails class
public class UserDetails {
public static string RateCountry { get; set; }
public static string RateWeek { get; set; }
public int Start { get; set; }
public int Length { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
Second Class
For now, its working like this. But I want to enhance it by making use of objects.
public static string RateCountry { get; private set; }
public static string RateWeek { get; private set; }
public ActionResult ShowList()
{
int start = Convert.ToInt32(Request["start"]);
int length = Convert.ToInt32(Request["length"]);
string name = Request["search[value]"];
string address = Request[("columns[3][search][value]")];
string rateType = Request[("columns[7][search][value]")];
if (string.IsNullOrEmpty(rateType)) // if null, reset the static variables to null
{
RateCountry = "";
RateWeek = "";
}
else
{
if (CheckDate(rateType)) // if contains date, assign to RateWeek
{
RateWeek = rateType;
}
else
{
RateCountry = rateType; // else if contains a string word, assing to ratecountry
}
}
var items = AssignDetails(start, length, name, address, RateWeek, RateCountry);
return items;
}
Then instead of passing several parameters like start, length, name etc. in the method AssignDetails, I can pass an object of the UserDetails class directly taking into consideration the static variables.
Can someone please help ?
Note: In C#, they are called properties not attributes. Attributes are a totally different thing.
What you want to do is straight forward:
Firstly, you need to change your method so it accepts your class UserDetails as an argument:
public void AssignDetails(UserDetails userDetails)
{
// Use userDetails here to do whatever you want
}
Secondly, when you call the above method, you need to pass the argument to it. You can create an instance of UserDetails and pass it to the AssignDetails method:
var userDetails = new UserDetails
{
Start = start,
Length = length,
Name = name
Address = address
}
I am not sure why RateWeek, and RateCountry properties are static in your class, but to set those you can do them as below (Please note it is using the class and not the instance of the class):
UserDetails.RateWeek = RateWeek;
You could make use of the instance's properties as an indirection to the class' static properties, although all this thing is really ugly in terms of design.
public class UserDetails
{
public static string PersistedRateCountry { get; set; }
public static string PersistedRateWeek { get; set; }
public static string RateCountry
{
get { return string.IsNullOrEmpty(rateType) ? "" : PersistedRateCountry; }
set { PersistedRateCountry = value; }
}
public static string RateWeek
{
get { return string.IsNullOrEmpty(rateType) ? "" : PersistedRateWeek; }
set { PersistedRateWeek= value; }
}
public static string RateWeek { get; set; }
public int Start { get; set; }
public int Length { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
I strongly suggest you to move these static properties out to another class, which would be responsible for persisting them.
E.g. try to separate your Data Object (which just holds data) from your Business Object (which contains business logic, and is constructed by receiving a Data Object as parameter). Put all that crazy persistence logic in the Business Object, and use the Business Object everywhere in your code (instead of using the Data Object).
Keep your classes short and clean. If you are coding a lot in the same class, it's probably because you got a bad object-oriented design.
I have the following code
class TopClass
{
public string ClsProp1 { get; set; }
public string ClsProp2 { get; set; }
public SubClass ClsProp3 { get; set; }
}
class SubClass
{
public string SCProp1 { get; set; }
public string SCProp2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
Test.TopClass TCN = new Test.TopClass();
TCN.ClsProp1 = "TCProp1--string value";
TCN.ClsProp2 = "TCProp2--string value";
TCN.ClsProp3.SCProp1 = "SCProp1--string value";
TCN.ClsProp3.SCProp2 = "SCProp2--string value";
}
}
I can't seem to figure out how to instantiate the TCN.ClsProp3.ScProp1 and TCN.ClsProp3.ScProp2 values. I keep getting the "An unhandled exception of type 'System.NullReferenceException' occurred in Test.exe
Additional information: Object reference not set to an instance of an object." error message. Forgive my ignorance, I'm really trying to learn OOP from scratch.
Thanks in advance
You need to initialize the ClsProp3 object before you can use it.
TCN.ClsProp3 = new SubClass();
You could also initialize it in the TopClass constructor like this:
class TopClass
{
public TopClass()
{
ClsProp3 = new SubClass();
}
public string ClsProp1 { get; set; }
public string ClsProp2 { get; set; }
public SubClass ClsProp3 { get; set; }
}
When learning, it's better to pick a good domain. TopClass with ClsPropX do not make for a nice learning experience.
As for your original question, launch the debugger and see what the ClsProp3 equals to. And bear in mind that it's impossible to assign anything to "nothingness", which is null in C# parlance.
I am currently developing a file indexing system. I have an interface IDiskDrive that can get immediate file items (files/folders). The interface definition is as follows...
public interface IDiskDrive
{
bool IsReady { get; }
string Name { get; }
string VolumeLabel { get; }
string VolumeLabelName { get; }
DiskDriveType Type { get; }
FolderPath RootFolder { get; }
DiskDriveUsage Usage { get; }
IEnumerable<IFileItem> GetImmediateFileItems(FolderPath path);
}
The ability to read all file/folders is complete and works correctly. Now, I need to actually index the file files and folders. Looking ahead I know I will need some reporting tools. This leads me to think I need another abstraction, based upon IDiskDrive that can read/populate. I also need the ability to select drives for indexing.
My question is should my new class inherit IDiskDrive or should I use composition (possibly a decorator)?
// inheritance
class IndexedDiskDrive : IDiskDrive
{
public IndexedDiskDrive(IDiskDrive drive)
{
...
}
public int Id {get; internal set; } // database id
public bool Selected { get; internal set; }
public DateTime? DateLastIndexed { get; internal set; }
// IDiskDrive implementation
public bool IsReady
{
get { return this.Drive.IsReady; }
}
}
or composition...
class IndexedDiskDrive
{
public IndexDiskDrive(IDiskDrive drive)
{
this.Value = drive;
}
public IDiskDrive Value
{
get;
private set;
}
// additional properties
public int Id { get; internal set; }
public bool Selected { get; internal set;}
public DateTime DateLastIndexed { get; internal set; }
}
Note:
I need access to the underlying IDiskDrive for the UI.
For example, I request user to select drives to index. I initially supply a list of local drives and the ability to add network drives. To try and keep code simple, I thought the idea of a new class with a selected property might help.
This allows the GUI to enumerate a list of IndexedDiskDrives and set/clear the select property.
In both examples you expose the IDiskDrive object from the other object. In the first case you inherit from the same inteface, which means you expose the same methods and in the other case you expose the object via a property.
I don't see a reason yet why you want to do this.
It sounds like a typical constructor DI case to me. Just have a new interface for your new class which is doing a different job and hence requires a different contract, and if it needs the IDiskDrive object as a dependency, then just inject it via the constructor and leave it as it is.
P.S.: I know this is not something you have asked, but you might be interested in Lucense.NET, which is a .NET library to index files. They might have already solved your problem for your:
http://lucenenet.apache.org/
EDIT:
From your current class design I would do the following:
void Main()
{
// Use IoC container in real app:
var diskDrive = new DiskDrive(...);
var fileIndexer = new FileIndexer();
var fileItems = diskDrive.GetImmediateFileItems(filePath);
fileIndexer.IndexFiles(fileItems);
}
// Define other methods and classes here
public interface IDiskDrive
{
bool IsReady { get; }
string Name { get; }
string VolumeLabel { get; }
string VolumeLabelName { get; }
DiskDriveType Type { get; }
FolderPath RootFolder { get; }
DiskDriveUsage Usage { get; }
IEnumerable<IFileItem> GetImmediateFileItems(FolderPath path);
}
public interface IFileIndexer
{
void IndexFiles(IEnumerable<IFileItem> files);
}
public class FileIndexer : IFileIndexer
{
public void IndexFiles(IEnumerable<IFileItem> files)
{
// do stuff
}
}
Over the past two years I developed apps for the CF .NET 3.5 to be runned on warehouse's portable device(windows mobile).
From the beginning I just jumped into the process and made a lot of mistakes that I'm gradually correcting. What has came out are apps made in this way:
a main form to start the whole process which automatically creates a data-form, that will stay alive for the whole time. This data-form will keep all the datas that the user will insert or request from the server. The other forms are basically views of the data with methods to manipulate them.
It works but...am I doing this in the right way? Or maybe am I missing something really fundamental?
So, you created a data form, and you are using it like RAM. You never display the data, you simply store it there to access.
If someone ever has to take over your job (like you leave the company or die), they are going to hate you so bad.
A better technique would be to create a Class that houses all of this data.
The good part is, since you already have a data form, you probably already know how everything is organized!
Now, just use that knowledge of your data to create your class that you can read and write to.
If you have groups of similar items, create other classes that your main class will contain.
If you have several of these similar items, create publically accessible Lists of these items.
Make it as dead simple or as complex as you'd like!
Consider these classes, which are all generic enough to modify however you would need and demonstrate some extras added:
public class DataForm {
private GroupedItem m_item2;
public event EventHandler Item2Changed;
public DataForm() { // this is your constructor
Item1 = new GroupedItem();
Item2 = new GroupedItem();
ItemCollection = new GroupCollectionItems("Group1");
}
public float Value1 { get; set; }
public float Value2 { get; set; }
public GroupedItem Item1 { get; set; }
public GroupedItem Item2 {
get { return m_item2; }
set {
if (m_item2 != value) {
m_item2 = value;
if (Item2Changed != null) {
Item2Changed(this, EventArgs.Empty); // notify whoever is listening for the change
}
}
}
}
public GroupCollectionItems ItemCollection { get; set; }
}
public class GroupedItem {
public GroupedItem() { // this is your constructor
}
public string Name { get; set; }
public object Value { get; set; }
}
public class GroupCollectionItem {
private GroupCollectionItem() { // this is your constructor
}
public static GroupCollectionItem Create(string groupName, string itemName, object itemValue) {
var item = new GroupCollectionItem() {
Group = groupName,
Name = itemName,
Value = itemValue
};
return item;
}
public string Group { get; private set; }
public string Name { get; private set; }
public object Value { get; set; }
}
public class GroupCollectionItems : List<GroupCollectionItem> {
public GroupCollectionItems(string name) { // this is your constructor
Name = name;
}
public string Name { get; private set; }
}
Let's say I have a class from a 3rd-party, which is a data-model. It has perhaps 100 properties (some with public setters and getters, others with public getters but private setters). Let's call this class ContosoEmployeeModel
I want to facade this class with an interface (INavigationItem, which has Name and DBID properties) to allow it to be used in my application (it's a PowerShell provider, but that's not important right now). However, it also needs to be usable as a ContosoEmployeeModel.
My initial implementation looked like this:
public class ContosoEmployeeModel
{
// Note this class is not under my control. I'm supplied
// an instance of it that I have to work with.
public DateTime EmployeeDateOfBirth { get; set; }
// and 99 other properties.
}
public class FacadedEmployeeModel : ContosoEmployeeModel, INavigationItem
{
private ContosoEmployeeModel model;
public FacadedEmployeeModel(ContosoEmployeeModel model)
{
this.model = model;
}
// INavigationItem properties
string INavigationItem.Name { get; set;}
int INavigationItem.DBID { get; set;}
// ContosoEmployeeModel properties
public DateTime EmployeeDateOfBirth
{
get { return this.model.EmployeeDateOfBirth; }
set { this.model.EmployeeDateOfBirth = value; }
}
// And now write 99 more properties that look like this :-(
}
However, it's clear that this will involve writing a huge amount of boilerplate code to expose all the properties , and I'd rather avoid this if I can. I can T4 code-generate this code in a partial class, and will do if there aren't any better ideas, but I though I'd ask here to see if anyone had any better ideas using some super wizzy bit of C# magic
Please note - the API I use to obtain the ContosoEmployeeModel can only return a ContosoEmployeeModel - I can't extend it to return a FacededEmployeeModel, so wrapping the model is the only solution I can think of - I'm happy to be corrected though :)
The other approach may be suitable for you is to use AutoMapper to map base class to your facade here is sample code:
class Program
{
static void Main(string[] args)
{
var model = new Model { Count = 123, Date = DateTime.Now, Name = "Some name" };
Mapper.CreateMap<Model, FacadeForModel>();
var mappedObject = AutoMapper.Mapper.Map<FacadeForModel>(model);
Console.WriteLine(mappedObject);
Console.ReadLine();
}
class Model
{
public string Name { get; set; }
public DateTime Date { get; set; }
public int Count { get; set; }
}
interface INavigationItem
{
int Id { get; set; }
string OtherProp { get; set; }
}
class FacadeForModel : Model, INavigationItem
{
public int Id { get; set; }
public string OtherProp { get; set; }
}
}
Resharper allows the creation of "delegating members", which copies the interface of a contained object onto the containing object and tunnels the method calls/property access through to the contained object.
http://www.jetbrains.com/resharper/webhelp/Code_Generation__Delegating_Members.html
Once you've done that, you can then extract an interface on your proxy class.