我有一个包含一堆属性的类.如果程序员在该类型的对象上调用ToString(),则这是一个错误.以此示例代码为例:
using System; public class Foo { public int ID = 123; public string Name = "SomeName"; private string ToString() { return null; } } public class MyClass { public static void Main() { Foo myObj = new Foo(); WL("I want this to be a compiler error: {0}", myObj.ToString()); RL(); } #region Helper methods private static void WL(object text, params object[] args) { Console.WriteLine(text.ToString(), args); } private static void RL() { Console.ReadLine(); } #endregion }
您可以推断,如果ID是大多数人想要写成字符串的内容,那么我应该实现ToString以便它返回ID.但是,我认为这是一种不好的做法,因为程序员会"意外地"获得工作代码.使用我的类的程序员应该指定他们想要的东西.
相反,我想要的是,如果有人调用myObj.ToString()将其显示为编译时错误.我以为我可以通过创建一个私有的ToString()函数来做到这一点,但这不起作用.
我提出这个问题的原因是我们最终得到的查询字符串包含完全限定的类名而不是ID.
所以问题是:有没有办法"隐藏"ToString()函数,以便在我的类的对象上调用它会导致编译器错误?
我不能强调这个设计有多糟糕.
ToString()
是.Net中对象契约的一部分.如果你不想实现它,那么不要覆盖它,只让它返回类型信息.这可能导致什么危害?
我并不是故意这么消极,但我绝对不知道有人想要摆脱它ToString()
.
一些额外的要点:
为什么使用这个类的程序员ToString()
会假设会返回一个ID?您生态系统中的其他类是否正在这样做?人们可以争辩说ToString()
应该返回一些有意义的数据.但你真的不应该针对ToString()
电话的结果进行编程. ToString()
用于类,句点的字符串表示.这听起来像是程序员或部门之间的教育或沟通问题.
ToString()
以任何方式瘫痪,无论你是否能够在编译时弄清楚如何在运行时抛出异常,都会产生涟漪.我从未见过这样做过,并且不会指望我使用任何类来表现出这种行为.我认为大多数程序员都会有同样的期望.未来使用你班级的程序员会期待这个吗?你在路上造成了什么错误和维护噩梦?
这对依赖的IDE或调试器有什么影响ToString()
?
使用不绑定特定类型的数据绑定技术时会产生什么影响,但在运行时使用反射来提取值?ToString()
如果未指定成员使用,则大多数数据绑定将回退到调用对象.
Obsolete属性允许您执行此操作.
[Obsolete("Use the XYZ properties instead of .ToString() on Foobar", true)]
最后的布尔值是编译器是否应该考虑使用此成员的错误.
出于某些原因,我完全不同意使用Obsolete属性.
首先,您将获得Tocetring()方法的警告,该方法使用Obsolete属性进行覆盖和标记:
[Obsolete("dont' use", true)] public override string ToString() { throw new Exception("don't use"); }
产生此警告:警告1过时成员'ClassLibrary1.Foo.ToString()'覆盖非过时成员'object.ToString()'d:\ source\ClassLibrary1\ClassLibrary1\Class1.cs 11 32 ClassLibrary1
所以现在你在代码中遇到了永久警告.除此之外,它并不能完全解决您的问题.当框架中的某些内容现在隐式调用ToString()时会发生什么?以下代码的结果是仍然调用ToString()体中的代码:
Foo myObj = new Foo(); Console.WriteLine(myObj);
所以现在你的代码中有一个警告,它实际上并没有阻止开发人员再次做同样的事情.我认为这里的正确举措是尝试找到一种在运行时抛出适当异常的方法,而不是试图弄乱.net对象契约.
建议在编译时捕获问题:我意识到我之前没有给出针对此问题的解决方案的建议.我真的不知道你的id是什么格式的,所以我只是猜测它是一个int,但为什么不保护用querystring创建url的任何东西并将id作为int传递.这样,开发人员不会在没有编译错误的情况下意外传入一些无意义的字符串.比如这样:
public string CreateItemUrl(int itemId) { return string.Format("someurl.aspx?id={0}", itemId); }
现在,打电话给:
CreateItemUrl(myObj.Id);
变得更强类型,更容易出错:
string theUrl = string.Format("someurl.aspx?id={0}", myObj);
我采取混合方式.(嘿,关于梳理其他答案不是吗?:))
首先,创建一个返回void的新ToString.没有返回值意味着他们不能使用它来获得任何意外的好代码:
public new void ToString() { }
接下来,添加Obsolete属性,这样当人们调用它时,他们会收到警告,告诉他们ToString是坏的.
你不需要以这种方式覆盖ToString,只需用无用的东西隐藏它.它没有返回的事实将破坏所有代码,因此在过时的消息之上导致编译器错误.
如果我直接理解你的问题,那么转换为对象的人不是你的问题.您不希望阻止人们调用ToString并获取类型信息,您希望防止他们意外地认为ToString提供了有用的结果.
编辑:请不要抛出异常或覆盖ToString.当您的对象被视为对象时,这会导致"坏事".只需使用"new"就可以获得您所要求的好处,而无需搞砸其他框架.