【问题标题】:How can I determine if ToString method is returning the object type name versus an actual value?如何确定 ToString 方法是否返回对象类型名称与实际值?
【发布时间】:2012-09-29 16:52:36
【问题描述】:

我打算使用 ToString() 方法来创建缓存键。该缓存将用于缓存方法级别的调用,并且将使用参数名称和相应的值构造键。由于此缓存将为大型库构建,因此我无法确保每个方法都只有值类型参数或所有类都实现序列化。我需要在运行时确定对 ToString 的调用返回的是实际值而不是类型名称,以便可以禁止该方法调用参与缓存。

对于实例,请考虑以下方法及其调用

AccountDetails GetDetails(int groupId, Account account)
{
    var ac1 = new Account( accountId = 123 };
    var ac2 = new Account( accountId = 555 };
    var return1 = GetDetails(15, ac1);
    var return2 = GetDetails(15, ac2);
}

在这种情况下,我会将缓存键构造为“groupId=15+account=namespace.Account”,从而导致不正确的冲突。如何在运行时检测到我对 account.GetString() 的调用将返回类型名称?

【问题讨论】:

  • 为什么要使用ToString 进行缓存?那不是它的目的。为什么不使用GetHashCodeEquals,它们通常更适合缓存 - 或者创建自己的接口来实现......
  • 是的,当 GetHashCode 已经被构建和定义以提供实例之间的良好区分时,想要解决停止问题以确定任意方法调用将返回什么似乎是绝对疯狂的.
  • 同意,ToString() 就是为此目的,从对象中提供人类可读的字符串。如果您真的想使用您提到的字符串作为缓存键,那么我会添加一些接口ICacheable,它提供string GetCacheKey()。但是使用字符串作为密钥不是效率低下吗?根据您的缓存方式,GetHashCode 无论如何都会在您的字符串上被调用。
  • @JonSkeet - 在我看来,这种情况类似于 Http 请求的输出缓存。确切的对象并不重要,但对象的价值很重要。我正在开发具有大量代码库的企业软件。我们知道我们将无法缓存每个边界调用的输出,但是对于只接受值参数的方法,可以通过从参数名称和值构建缓存键来实现。这就是为什么不提供的 ToString() 和 opt out 引用类型是合适的值。
  • @zync:听起来GetHashCodeEquals正是你应该使用的,而不是字符串表示。例如,您只能接受实现 IEquatable<T> 的类型。这将提供比使用 ToString、IMO 更好的体验。

标签: .net caching tostring


【解决方案1】:

您不应该将字符串用于一般缓存键。这真的不是 ToString 的设计目的。相反,您应该使用EqualsGetHashCode 来检查是否相等。当然,就像ToString,每个对象都有EqualsGetHashCode 方法……但幸运的是,IEquatable<T> 接口提供了一个非常更强烈的信号,表明一个类型真的是为平等而设计。

所以对于任何给定类型X,只需检查该类型是否实现IEquatable<X>。如果是这样,那么用作缓存键应该是合理的。如果您正在编写通用方法,则可以强制执行:

void Foo<T>(T key, /* other parameters */) where T : IEquatable<T>

【讨论】:

  • 所以理论上这是可行的,但对于我的具体情况,我需要从传入的“对象”中获取哈希码。问题是,我似乎可以确定传入的对象是否实现 IEquatable 的唯一方法是执行 target.GetType().GetInterface(typeof(IEquatable).FullName)。这会导致反射并影响性能。
  • @zync:不幸的是,你没有给我们足够的上下文来帮助你 - 我们不知道你是否有一个通用方法等。你可以很容易地按类型保留缓存,虽然您根本不需要使用 name - 使用 typeof(IEquatable&lt;&gt;).MakeGenericType(target.GetType()) 然后检查该类型是否实现了该特定接口。
  • 抱歉(这里是凌晨 3 点)。不 - 我没有通用功能。我正在使用统一拦截来拦截功能。我收到的是有关拦截的方法和参数“对象”集合的信息。我需要弄清楚这些对象是否可以成为 GetHashCode + Equals 的候选对象。我会试试你提到的;另一个选项似乎是 target.GetType().GetInterfaces(),然后将字符串与 typeof(IEquatable).FullName 进行比较。但是您的建议似乎比类型名称上的字符串比较更可靠。
  • @zync:它也应该更快 :) 您可以使用Type.IsAssignableTo 作为检查接口实现的一种方法(还有其他各种方法)。但是从类型缓存到“这是否有效”可能很值得做。
  • 嗯。是的。这样可行。将检查性能。幸运的是,这将在服务器端运行 :)
【解决方案2】:

我不知道“ToString”方法中的实现是什么(就你所知,有人在“Object”中重载了“ToString”,但实现方式与在“Object”中实现的方式相同)。

您不能将 ToString 用作对象的一种哈希。考虑两个逻辑上不同的对象,例如两个具有相同全名和不同 ID(或一些非 ascii 值,如图片)的“学生”对象。您需要使用真正的哈希 - 请参阅“GetHashCode”。

如果“GetHashCode”不是一个选项,我们将需要更多信息(例如“为什么”)

【讨论】:

  • 不是答案(更多评论,与现有评论相同)
  • 请注意,GetHashCode 不应单独使用。与加密哈希不同,来自对象的哈希码在易于创建的情况下完全可以合理地发生冲突。 GetHashCode 应该用作检查相等性的第一步,而不是最后一步。
猜你喜欢
  • 2017-01-25
  • 1970-01-01
  • 2018-11-19
  • 2021-09-28
  • 1970-01-01
  • 2015-11-25
  • 1970-01-01
  • 2010-11-09
  • 1970-01-01
相关资源
最近更新 更多