使用静态对象

时间:2009-09-26 00:04:09

标签: c#

我的理解是,任何不修改constaining类状态的方法都是静态的主要候选者,因为它不会触及实例。一个实例将包含类的数据(字段/属性),所以如果我有一个人类,其中包含一个名为Name的属性(只有一个属性),并且我没有修改该属性,那么我的类可以设置为静态,但是当然,但该功能可以与另一个对象一起工作。在检查方法是否应该是静态时,这是正确的选择吗?

静态变量被描述为全局变量,但这与任何公共变量的区别是什么?所有变量都在服务器的内存中,并在重启等时丢失。然后使用此变量来保存昂贵的数据(例如,在循环中运行存储过程等)。

由于

5 个答案:

答案 0 :(得分:3)

  

我的理解是,任何不修改constaining类状态的方法都是静态的主要候选者,因为它不会触及实例。

我不会说这是 prime 候选人,而只是候选人。就个人而言,我认为如果API从逻辑算法的角度来看它应该是静态的,那么方法应该是静态的。从技术上讲,任何不改变状态的方法都可以是静态的,但我不认为它必然是静态的。

  

并且我没有修改该属性,然后我的类可以设置为静态,但当然,但该函数可能正在使用另一个对象。

如果它绝对没有实例变量,你只能在C#中将你的类设置为静态。静态类的“实例”不存在(并且不存在),非静态成员也不存在。

现在 - 因为我认为你真的在追求......

静态变量和非静态变量之间的区别与它的访问方式有关。当您在类上定义静态字段时,您将定义一个字段,该字段始终具有与类本身相关联的单个实例(字段的实例)。另一方面,当您定义非静态的普通字段时,您可能会有许多字段实例,每个实例都位于您的类的一个实例中。

这就是静态变量通常被描述为全局的原因 - 任何有权访问该类的东西都可以访问它的静态变量的一个副本(如果它是公共可访问的)。但是,非静态字段是不同的 - 您需要引用该类的特定实例才能读取或写入非静态成员。

答案 1 :(得分:2)

  

我的理解是任何方法   不修改状态   保持[原文]类是一个主要的候选人   因为它不是静止的   触摸实例。

我不认为这是考虑静态与非静态的正确方法。相反,任何相关 类实例的状态的方法都可以是静态的。名称显然与特定人员相关联,因此Name类上的Person字段几乎肯定是静态的。否则,你可能会得到这样的场景:

public class Person {
    public static string Name { get; set; }

    public Person(string name) { Name = name; }

    public override string ToString() {
        return Name;
    }
}

Person dan = new Person("Dan";
Person john = new Person("John";

// outputs "John"
Console.WriteLine(john);

// outputs "John" again, since Dan doesn't have a name property all his own
// (and neither does John, for that matter)
Console.WriteLine(dan);

编辑:现在,假设我们拥有House这样的属性,它可以属于不是一个人而是几个人。刀片问:“这将如何在代码中建模 - 静态?”

我的回答:不,原因与上面提到的相同。假设我通过使Name属性非静态来解决上述问题。然后我介绍一个新的静态House属性。现在我有这样的情况:

public class Person {
    public string Name { get; set; }
    public static House House { get; set; }

    public Person(string name, House house) {
        Name = name;
        House = house;
    }

    public override string ToString() {
        return String.Concat(Name, ", ", House);
    }
}

public class House {
    public double SquareFootage { get; set; }

    public House(double sqft) { SquareFootage = sqft; }

    public override string ToString() {
        return String.Format("House - {0} sq. ft.", SquareFootage);
    }
}

House danAndKatsHouse = new House(1000.0);
House johnsHouse = new House(2000.0);

Person dan = new Person("Dan", danAndKatsHouse);

// outputs "Dan, House - 1000 sq. ft." as expected
Console.WriteLine(dan);

Person kat = new Person("Kat", danAndKatsHouse);

// outputs "Kat, House - 1000 sq. ft.", again as expected
Console.WriteLine(kat);

Person john = new Person("John", johnsHouse);

// outputs "John, House - 2000 sq. ft.", so far so good...
Console.WriteLine(john);

// but what's this? suddenly dan and kat's house has changed?
// outputs "Dan, House - 2000 sq. ft."
Console.WriteLine(dan);

共享相同对象的一个​​类的多个对象与共享同一对象的该类的 ALL 对象之间存在差异。在后一种情况下,静态属性是有意义的;否则,它没有。

有一些方法可以解决这个问题。他们是:

1。使House属性非静态

这可能看起来很奇怪,但你总是可以让House属性非静态,你不必担心上面的问题。此外,假设您实际上为共享它的每个House分配了相同的Person对象,通过一个House对象对Person进行更改实际上会达到预期的效果:

House danAndKatsHouse = new House(1000.0);

// (after making Person.House property non-static)
Person dan = new Person("Dan", danAndKatsHouse);
Person kat = new Person("Kat", danAndKatsHouse);

dan.House.SquareFootage = 1500.0;

// outputs "1500"
Console.WriteLine(kat.House.SquareFootage);

这实际上可能是一个问题,但是,如果你不小心将同一个House分配给两个人,意图他们实际上有两个不同的房子:

House smallerHouse = new House(1000.0);
House biggerHouse = new House(2000.0);

Person dan = new Person("Dan", smallerHouse);
Person john = new Person("John", biggerHouse);
Person bill = new Person("Bill", smallerHouse);

bill.House.SquareFootage = 1250.0;

// yikes, Dan's house just changed...
Console.WriteLine(dan);

2。使用数据库

事实上,将房子作为人的财产的概念在某种程度上是一个强迫的概念。一个人可能搬出他们的房子,不同的人可能会搬进来等。两者之间确实存在关系,这使得使用数据库成为一个合适的解决方案。

使用这种方法,你要做的是有一个Persons表,一个Houses表和一个第三个表(可能是PersonHouses),其中包含来自其他两个表的id对我想是代表房屋所有权。

如果您没有可供使用的完整数据库,则可以在代码中使用System.Data.DataSet及其System.Data.DataTable对象集合实现相同的结果(在.NET中) 。但是,在将数据库(或DataTable)的行转换为对象然后再转换回来的任何情况下,您都需要了解impedence mismatch。基本上,一旦数据在数据库中,您在代码中封装数据时采取的一丝不苟的预防措施就会出现在窗口之外,任何拥有足够权限的人都可以对其进行修改。

3。使用词典

另一种方法,类似于使用数据库,但更多的工作(我认为一些程序员已经走了DataSet路线一想到这一点不寒而栗),就是使用词典来跟踪你的PersonHouse个对象。实现此方法的最快方法是拥有Dictionary<int, Person>Dictionary<int, House>,并为每个Person分配HouseId属性:

public class Person {
    public int Id { get; private set; }
    public string Name { get; set; }
    public int HouseId { get; set; }

    private static int LastIdValue { get; set; }
    private static Dictionary<int, Person> People { get; set; }

    static Person() {
        LastIdValue = 0;
        People = new Dictionary<int, Person>();
    }

    // make the constructor private to disallow direct instantiation
    private Person(int id, string name, int houseId) {
        Id = id;
        Name = name;
        HouseId = houseId;
    }

    // only permit construction through this function, which inserts
    // the new Person into the static dictionary before returning it
    static public Person NewPerson(string name, int houseId) {
        Person p = new Person(LastIdValue++, name, houseId);
        People.Add(p.Id, p);
        return p;
    }

    static public Person getPersonById(int id) {
        Person p = null;
        return People.TryGetValue(id, out p) ? p : null;
    }
}

public class House {
    public int Id { get; private set; }
    public int SquareFootage { get; set; }

    private static int LastIdValue { get; set; }
    private static Dictionary<int, House> Houses { get; set; }

    static House() {
        LastIdValue = 0;
        Houses = new Dictionary<int, House>();
    }

    // make the constructor private to disallow direct instantiation
    private House(int id, int sqft) {
        Id = id;
        SquareFootage = sqft;
    }

    // only permit construction through this function, which inserts
    // the new House into the static dictionary before returning it
    static public House NewHouse(int sqft) {
        House h = new House(LastIdValue++, sqft);
        Houses.Add(h.Id, h);
        return h;
    }

    static public House getHouseById(int id) {
        House h = null;
        return Houses.TryGetValue(id, out h) ? h : null;
    }
}

House firstHouse = House.NewHouse(1000.0);
House secondHouse = House.NewHouse(2000.0);

Person dan = Person.NewPerson("Dan", firstHouse.Id);
Person kat = Person.NewPerson("Kat", firstHouse.Id);
Person john = Person.NewPerson("John", secondHouse.Id);

House dansHouse = House.getHouseById(dan.HouseId);
House katsHouse = House.getHouseById(kat.HouseId);

// this prints
if (katsHouse == dansHouse) { Console.WriteLine("Dan and Kat live in the same house."); }

// this also prints
if (dansHouse == firstHouse) { Console.WriteLine("Dan and Kat live in the first house."); }

// this does not print
if (dansHouse == secondHouse) { Console.WriteLine("Dan and Kat live in the second house."); }

这样,您的所有数据封装仍然存在。但是,如果您需要在运行的代码实例之间保留数据,那么您需要以某种文件格式(很可能是XML)序列化字典,然后可以由具有足够权限的任何人编辑,然后您就可以了回到重新使用数据库的阻塞不匹配问题。

鉴于每种方法的优点和缺点,我认为实际上最有意义的 - 并且让您的生活最简单 - 就是简单地使House成为非静态属性。假设您没有大量的PersonHouse个对象来跟踪。

答案 2 :(得分:1)

  

“如果我有一个人的课程   名为Name的属性(就是那个   一个属性),我没有修改   那个属性然后我的类可以设置   作为静态“

这是不正确的。人员类几乎肯定是域实体。可以想象你可能想在Person实体上有一个静态方法,但我从来没有遇到过。在您的示例中,您将拥有“名称”属性的私有设置器。

任何事情的静态都应该为您的域建模,而不是语言实现细节。

答案 3 :(得分:0)

在C#中没有真正的globl变量,因为该术语在其他语言中使用,例如C.静态对象和全局对象之间的区别在于静态对象具有相对于类中的类的权限它是定义的。这是一件非常好的事情,因为您可以创建只能由一个类的成员访问的私有静态成员。滥用全局变量的一个大问题是对单个全局变量的许多依赖性,这些变量可以在大量模块集合中发展。私有静态对象可以避免这个问题。

静态对象的一个​​大问题是它们不是线程安全的。为了声明线程安全的静态对象,必须使用ThreadStatic属性并提供在第一次访问时初始化对象的方法。您应该为所有多线程环境执行此操作,例如ASP.NET,以及可能在多线程环境中运行的任何通用库。哎呀,总是这样做,你不会后悔!

答案 4 :(得分:0)

如果您的Person类具有静态字段名称:

public class Person {
    public static string Name { get; set; }
}

然后你只能拥有一个名字。您不能拥有不同姓名的人员名单。静态可以被视为“唯一”,因为它的价值是全球的。顺便说一句,这可能是ASP.net应用程序中的陷阱,因为静态应用于整个应用程序,这意味着对所有用户。

静态变量非常罕见,用于实际上不属于该类特定实例的数据。或者返回特定的实例。

例如,Guid.Empty是一个静态字段,它返回一个将所有Bits设置为0的Guid。

一个很好的例子是System.Drawing.Color。 Color具有特定于实例的变量,例如R,G,B和Alpha,但是您有像Color.Black这样的静态字段,它返回黑色。