Click here to Skip to main content
14,207,305 members
Rate this:
 
Please Sign up or sign in to vote.
See more:
OK, this may be hard to explain so forgive me if you don't understand any of it. I am porting some of my functions that were previously in classes in my main application into a class library so I can use them in any projects. I have literally just started this so the code might not be very complete but I have this so far:
namespace WeatherLink
{
    public class DataDownloader
    {
        public class MetOffice
        {
            public DataType DataType;
            public bool CacheData;
            public string CacheLocation;
            public string ApiKey;

            public string GetData()
            {
                string resource = "";

                if (DataType.Type == "VisibleObservation")
                {
                    string sourcePath = string.Format(Path.Combine(@"C:\Users\Henry\AppData\Local\WeatherLink\temp\runtime_cache\visibleObservation"));

                    if (!File.Exists(sourcePath))
                    {
                        string sourceImage = string.Format("http://datapoint.metoffice.gov.uk/public/data/layer/wxobs/SATELLITE_Visible_N_Section/png?TIME={0}Z&key={1}");
                        System.Drawing.Bitmap image = new Bitmap(Image.FromStream(System.Net.HttpWebRequest.Create(sourceImage).GetResponse().GetResponseStream()));
                        Bitmap bitmap = new Bitmap(640, 852);
                        using (Graphics graphics = Graphics.FromImage(bitmap))
                        {
                            graphics.DrawImage(image, new Point[] { new Point(0, 0), new Point(650, 0), new Point(0, 852) });
                            bitmap.Save(sourcePath);
                            resource = sourcePath;
                        }
                    }
                    else { resource = sourcePath; }
                    return resource;
                }

                return resource;
            }
        }

        public class EuMetSat
        {

        }
    }

    public class DataType
    {
        public string Type { get; set; }
    }
}

...and I call it like this:
DataDownloader.MetOffice MetOffice = new DataDownloader.MetOffice();
DataDownloader.EuMetSat EuMetSat = new DataDownloader.EuMetSat();

I want to know how I can change my code in the library so that I can call a DataDownloader like this:
DataDownloader dd = new DataDownloader(MetOffice);
DataDownloader dd = new DataDownloader(EuMetSat);

...So instead of calling it using all the levels of the namespace I want to call the DataDownloader and specify its type (either MetOffice or EuMetSat). How do I do this? Would I have to use methods instead of classes for the 2 types? Like when you initiate most variables, as an example an XmlDocument has brackets after it (new XmlDocument()) where you could specify something for it. How would I do this in my code (new DataDownloader(MetOffice))? I hope you understand what I am trying to do. Thank You
Posted
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 4

I started to write my response before there were other solutions posted here, but I see that what I did is different from the other responses: I maintain your nested Classes, and do not use an Abstract Class.

Hopefully, in the range of implementations here, you'll find useful ideas to adapt to your own work.

Consider this:
using System;

namespace WeatherLink
{
    public class DataDownLoader
    {
        public DataDownLoader()
        {
            // initialize data structures, fields, properties
            // common to both MetOffice and EuMetSat
        }

        // declare data structures, fields, properties
        // common to both MetOffice and EuMetSat
        // these can be public or private
        private string ClassName;

        // create methods and functions
        // common to both MetOffice and EuMetSat
        // these can be public or private
        public void WriteToConsole()
        {
            if (this is MetOffice)
            {
                Console.WriteLine("This is a MetOffice instance");
            }
            else if (this is EuMetSat)
            {
                Console.WriteLine("This is a EuMetSat instance");
            }
            else
            {
                throw new ArgumentException("Error in argument to WriteToConsole");
            }
        }

        public class MetOffice : DataDownLoader
        {
            public MetOffice()
            {
                ClassName = "MetOffice";
            }
        }

        public class EuMetSat : DataDownLoader
        {
            public EuMetSat()
            {
                ClassName = "EuMetSat";
            }
        }
    }
}
In this case, the outer Class is simply serving as a binder for the inner Classes, providing common functionality.

Here you would create new instances of the inner Classes, each of which inherits from the outer Class, like this:
WeatherLink.DataDownLoader newMetOffice = new WeatherLink.DataDownLoader.MetOffice();

WeatherLink.DataDownLoader newEuMetSat = new WeatherLink.DataDownLoader.EuMetSat();
In OOP terms we can say that each instance of MetOffice, and EuMetSat, is-a instance of 'DataDownLoader.

Each instance of MetOffice, or EuMetSat, can call the public method 'WriteToConsole provided by the DataDownLoader Class: in that method the keyword 'this is used to get the Type of the current "flavor" of DataDownLoader:
newMetOffice.WriteToConsole();
newEuMetSat.WriteToConsole();
If I may suggest, I think it's very important to try and get a basic grounding in OOP concepts in .NET from the beginning, and understanding inheritance, and use of abstract and virtual Classes, and Interfaces, are very important. A good book, or two, and study, and posing design problems to yourself, will equip to handle many scenarios in the future (end of sermon).

Finally, there are many ways you could implement the functionality you have specified here (if I understood it !); I don't claim the way I presented here is the "ultimate."
   
v2
Comments
Henry Hunt 15-Nov-13 16:00pm
   
This works, thank you but where would I write my main code to do things like actually download the data? I'm a bit confused as to which classes do what
BillWoodruff 15-Nov-13 20:10pm
   
Hi Henry, I suggest you take methods which both MetOffice and EuMetSat can use in the same way and make them methods of the outer Class, DataDownLoader.

Depending on what you need the method to do ... i.e., return something, or just transform something, then write methods specific to each internal Class that invoke the shared method in the outer Class.

Similarly, each internal Class should define internal fields, properties, etc., which are unique to the Class.

A guiding principle in Class design is "separation of concerns:" in this case, MetOffice should not "know" about, or have access to the internal private state of EuMetSat ... unless, of course MetOffice needs to interact with EuMetSat: in that case they should interact through public methods in the outer Class.

Those "things" you wish your Class to expose to users of the Class (consumers), should be exposed via public properties, or methods.
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 1

AFAIK, you can't - because new always returns an instance of the class you create, and you can't change that: so it will always return a DataDownloader class instance.
But it would be simple (ish) to add a Create method to DataDownloader that takes a Type and creates it:
public static T Create<T>() where T : new()
    {
    return new T();
    }
But frankly, I wouldn't go there.

Myself, I would create DataDownLoader as an abstract base class, and derive MetOffice and EuMetSat from it, since your containing class seems to exists simply to "bracket" the two classes within it.
   
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 2

Well the first thing to do is not nest your classes if there is no need to, so here is a stripped down example:

interface IWeatherDataSource
{
    //Define common interface to your data source here
}

class DataDownloader
{
    DataDownloader(IWeatherDataSource dataSource)
    {
        //Do whatever with your source here
    }
}

class MetOffice : IWeatherDataSource
{
    //Implement IWeatherDataSource
}

class EuMetSat : IWeatherDataSource
{
    //Implement IWeatherDataSource
}


Then elsewhere in your program, you can write:

DataDownloader metSource = new DataDownloader(new MetOffice());
DataDownloader euSource = new DataDownloader(new EuMetSat());
   
Comments
PIEBALDconsult 15-Nov-13 15:40pm
   
Or generic: new DataDownloader<EuMetSat>()
Henry Hunt 15-Nov-13 15:43pm
   
THAT'S IT!! That's what I want, like a list<>
PIEBALDconsult 15-Nov-13 15:53pm
   
I trust you've written generic classes before?
Ron Beyer 15-Nov-13 15:58pm
   
Even with generics he's still going to have to implement a common interface, and use generic constraints, like:

class DataDownloader<T> where T : IWeatherDataSource, new()
{
T internalSource;

DataDownloader()
{
internalSource = new T();
}
}
PIEBALDconsult 15-Nov-13 16:09pm
   
Yes.
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 3

# define DataDownloader(x) DataDownloader.x()

var d = new DataDownloader(MetOffice);


But seriously, I think your example is flawed, you likely need an abstract class and/or an Interface. You may also want to go generic.
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Advertise | Privacy | Cookies | Terms of Service
Web04 | 2.8.190612.1 | Last Updated 15 Nov 2013
Copyright © CodeProject, 1999-2019
All Rights Reserved.
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100