在类库中创建类似'class(type)'的类/函数 [英] Making a class/function that works like 'class(type)' in a class library

查看:95
本文介绍了在类库中创建类似'class(type)'的类/函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,这可能很难解释,如果你不理解,请原谅我。我将以前在我的主应用程序中的类中的一些函数移植到类库中,以便我可以在任何项目中使用它们。我刚刚开始这样做,所以代码可能不是很完整但我到目前为止:

  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}ž&安培;键= {1});
System.Drawing.Bitmap image = new 位图(Image.FromStream(System.Net.HttpWebRequest.Create(sourceImage).GetResponse()。GetResponseStream() ));
位图位图= 位图( 640 852 );
使用(图形图形= Graphics.FromImage(位图))
{
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 资源;
}

return 资源;
}
}

public class EuMetSat
{

}
}

public class DataType
{
public string 类型{获得; set ; }
}
}



......我称之为:

 DataDownloader.MetOffice MetOffice =  new  DataDownloader.MetOffice(); 
DataDownloader.EuMetSat EuMetSat = new DataDownloader.EuMetSat();



我想知道如何我可以在库中更改我的代码,以便我可以像这样调用DataDownloader:

 DataDownloader dd =  new  DataDownloader(MetOffice); 
DataDownloader dd = new DataDownloader(EuMetSat);



...所以不要叫它使用命名空间的所有级别我想调用DataDownloader并指定其类型(MetOffice或EuMetSat)。我该怎么做呢?我是否必须使用方法而不是两种类的类?就像你启动大多数变量一样,作为一个例子,XmlDocument后面有括号(new XmlDocument()),你可以为它指定一些东西。我将如何在我的代码中执行此操作(新的DataDownloader(MetOffice))?我希望你明白我想做什么。谢谢

解决方案

我在这里发布了其他解决方案之前就开始写我的回复,但我看到我所做的与其他回复不同:我维护你的嵌套的类,不要使用抽象类。



希望在这里的实现范围内,你会找到适合你自己工作的有用的想法。 br />


考虑一下:

 使用系统; 

命名空间 WeatherLink
{
public class DataDownLoader
{
public DataDownLoader()
{
// 初始化数据结构,字段,属性
// MetOffice和EuMetSat共有
}

// 声明数据结构,字段,属性
// MetOffice和EuMetSat共有
// 这些可以是公共或私人
私人 string ClassName;

// 创建方法和函数
// MetOffice和EuMetSat共有
// 这些可以是公共的或私有的
public void WriteToConsole()
{
if this < span class =code-keyword> MetOffice)
{
Console.WriteLine( 这是一个MetOffice实例);
}
其他 如果 EuMetSat)
{
Console.WriteLine( 这是一个EuMetSat实例);
}
其他
{
throw new ArgumentException( WriteToConsole参数出错 );
}
}

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

public class EuMetSat: DataDownLoader
{
public EuMetSat()
{
ClassName = EuMetSat;
}
}
}
}

在这种情况下,外部类只是作为内部的绑定器类,提供通用功能。



在这里你将创建内部类的新实例,每个实例都继承自外部类,如下所示:

 WeatherLink.DataDownLoader newMetOffice = new WeatherLink.DataDownLoader.MetOffice(); 

WeatherLink.DataDownLoader newEuMetSat = new WeatherLink.DataDownLoader.EuMetSat();

在OOP术语中,我们可以说MetOffice的每个实例和EuMetSat,是-a 'DataDownLoader的实例。



MetOffice或EuMetSat的每个实例都可以调用DataDownLoader类提供的公共方法'WriteToConsole:在该方法中keyword'这用于获取DataDownLoader的当前风格的类型:

 newMetOffice.WriteToConsole(); 
newEuMetSat.WriteToConsole();

如果我可以建议,我认为从一开始就尝试从.NET中获取OOP概念的基础知识,理解继承和使用是非常重要的。抽象和虚拟类以及接口非常重要。一本好书,或者两本书,学习,并为自己设计设计问题,将来可以处理许多场景(布道结束)。



最后,您可以通过多种方式实现此处指定的功能(如果我理解的话);我没有声称我在这里呈现的方式是终极。


AFAIK,你不能 - 因为总是返回你创建的类的实例,你不能改变它:所以它总是会返回一个DataDownloader类实例。

但是向DataDownloader添加一个Create方法会很简单(ish)接受一个Type并创建它:

  public   static  T创建< T>()其中 T: new ()
{
return new T();
}

但坦率地说,我不会去那里。



我自己,我会创建一个<$ c $的DataDownLoader c> abstract 基类,并从中派生MetOffice和EuMetSat,因为你的包含类似乎只是为了括起其中的两个类。


那么首先要做的就是不用嵌套你的课程,所以这里有一个简单的例子:



  interface  IWeatherDataSource 
{
// 在此处定义数据源的通用接口
}

class DataDownloader
{
DataDownloader(IWeatherDataSource dataSource)
{
// 在这里对你的来源做任何事情
}
}

class 遇见Office:IWeatherDataSource
{
// 实现IWeatherDataSource
}

class EuMetSat:IWeatherDataSource
{
// 实施IWeatherDataSource
}





然后在程序的其他地方,你可以写:



 DataDownloader metSource =  new  DataDownloader( new  MetOffice()); 
DataDownloader euSource = new DataDownloader( new EuMetSat());


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

解决方案

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."


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.


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());


这篇关于在类库中创建类似'class(type)'的类/函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆