如何向属性添加方法?

8
假设我创建了一个带有属性的类:
```

假设我创建了一个带有属性的类:

```
public class User
{
   private string _userID;

   public string UserID
   {
      get { return _userID; }
      set { _userID = value; }
   }
}

我需要对类和属性进行哪些处理,才能将方法附加到UserID属性上,例如使用“点”语法生成围绕用户ID的Xml呢?
User u = new User();
u.UserID = "Mike";
string xml = u.UserID.ToXml();

我可以想出如何编写一个方法来在UserID的值周围放置Xml标记,但让我困扰的是如何让该方法与使用“点”语法的属性一起工作。
所有这些答案都很有用,感谢大家的贡献。事实上,我标记为“已接受”的答案正是我要找的。我感谢关于扩展方法的警告(在此之前我从未听说过),当然,在某些情况下将扩展方法应用于所有字符串可能会成为问题,但在这种情况下,我绝对想将ToXml()方法应用于类中的所有字符串属性。正合我意。我非常熟悉XmlSerialization,但在这种情况下需要避免它出于各种原因。
9个回答

14

有两种方法:

要么你操作的对象/值必须具有该方法(例如当你控制对象定义时)。

public class UserIDObject
{
   public string ToXML() {}
}

public class User
{
   private UserIDObject _userID;

   public UserIDObject UserID
   {
      get { return _userID; }
      set { _userID = value; }
   }
}

User u = new User();
u.UserID = = new UserIDObject("Mike");
string xml = u.UserID.ToXml();

或者你可以为该对象实现一个 扩展方法 (MSDN)。 Geeks with blogs 上有一个很好的 扩展方法 教程,如果你正在使用 VS2008,它们可以应用于 .NET 2.0。

public static class MyMethods
{
    public static string ToXML(this string s) { }
} 

扩展方法是你想要重视的东西,因为扩展方法适用于该类类型的所有对象。(例如,我是否想让所有字符串都能调用.ToXML()?)


请记住,扩展方法将影响所有字符串,这可能是您想要的,也可能不是。 - Herms
非常好的回答... 你可能想要添加将数据隐式转换为他原本期望的数据类型(int)。 - Timothy Khouri
@Tim - 抱歉,我不明白你所说的隐式转换为int数据类型是什么意思。 - Gavin Miller

7
你可以选择以下两种方法之一:
  1. 将_userID更改为自定义类,将字符串包装起来并添加所需的方法。
  2. 为字符串类创建一个扩展方法(不建议这样做),这将影响所有字符串对象。

与“LFSR Consulting”的评论相同...但仍然是正确的答案 :) - Timothy Khouri
他实际上比我更快地发布了它 :S - Ben S
这更加直接,即使稍晚一点发布,因此更有可能被阅读和理解。 - Joel Coehoorn

5

您需要将该方法添加到属性的类型中。在这种情况下,UserID是一个字符串,这意味着需要将它添加到字符串类型中,并使其可从所有字符串访问。我不确定这是否是一个好主意,但如果这确实是您想要做的:

public static class StringUtils
{
    public string ToXmlElement(this string s, string elementName)
    {
       return string.Format("<{0}>{1}</{0}>", elementName, s);
    }
}

这与您的函数签名并不完全匹配,但将其附加到更大的字符串类上会更有意义。唯一的其他选择是使用不同的基础类型来保存您的UserID,可能是一个带有隐式转换为字符串的自定义类。
最后,如果您只是想以通用方式编写用户类到Xml,请查看System.Xml.Serialization命名空间。然后,您可以像这样标记您的类,并使用XmlSerializer实例来读取或写入该类。
[Serializable]
public class User
{
   private string _userID;

   [XmlElement()]
   public string UserID
   {
      get { return _userID; }
      set { _userID = value; }
   }
}

由于这个回答被接受了,我编辑了问题并包含了其他人提出的一些好点子。 - Joel Coehoorn

2
在C# 3.0中,有几种方法可以完成此任务,一些方法更直接,类似于您想要的操作方式,而另一些则不是。首先,让我澄清一下为什么您可能立即无法确定如何完成此操作:
由于您指定的UserID属性是string类型,因此它的所有成员都已定义,并且限于String的成员(至少在传统的面向对象编程[OOP]中是这样)。当然,这包括方法。您似乎想添加一个ToXml方法,但是如果没有访问属性类型(在这种情况下为System.String),则不可能实现该方法。
因此,您的选择如下:
  1. Change the type of the property to a custom class (i.e. a UserIdentification class) and add the ToXml method to this. Not a very good solution in most cases to be honest, as it adds unnecessary complexity. Consider it only if you will need to add multiple methods/properties related to UserID.

  2. Simply add the ToXml method to your User class (and call it something like GetIdXmlString). A decent solution, and probably what I would have chosen before C# 3.0 (and possibly still, depending on the circumstances).

  3. Extension methods. This is a great feature added to the latest version of C#, which allows you to "extend" existing classes and interfaces by adding methods to them defined with a special syntax. See the linked article for more information, but your extension method will essentially look like this:

    public static string ToXml(this string str)
    {
        // Code for function goes here.
    }
    

    You can then simply call this method as if it actually belonged to the string class. Take care however, as this last method may not always be appropiate (since it can be applied to all objects of type string in your code). If you want to write a generic ToXml function (with overloads?) that converts various objects into your own custom XML format, then fair enough, otherwise you may be better off with the 2nd suggestion. A helper class is another alternative, and although the syntax is slightly less nice it does at least mean that the ToXml method doesn't appear for all strings.

无论如何,希望这有所帮助...

2

简而言之,虽然通过扩展方法实现可能是可行的,但你不想这样做。这是不好的形式,也不一定是你想要的。

更好的技术应该利用.NET XML序列化并将其传递给你的对象。它可以为你做XML魔法。


0

我猜你可以非常巧妙地通过AOP进行属性移除,用一个代理类替换该属性,并具有正确的方法。但即使你这样做了,你可能仍需要将新属性强制转换为某个接口 - 实际上是双重转换,例如,

IXmlable x = (IXmlable)(object)this.UserId;
x.ToXml();

这可能会打破一开始做它的初衷。但是,至少你会得到关注点分离,对吧?

说真的,我会选择上面提到的其他更简单的选择。除非你想成为AOP大师。 :)


0

好的,你不会使用 String 类型来做这件事。你需要创建一个新类,该类具有所有必要的字符串处理方法,但也实现了你的 "ToXml()" 方法。不幸的是,你不能直接从 string 类派生,因此你需要实现包装器方法或其他方式来提供你想要的字符串处理功能。


0

不是使用字符串,而是需要一个支持ToXml()方法的类。


0
你可以创建一个名为 struct UserID 的值类型,并在其中添加方法,然后在你的类中使用它,而不是使用 string

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接