我可以用什么hack来定义一个与类同名的c#属性?

本文关键字:属性 一个 hack 什么 定义 我可以 | 更新日期: 2023-09-27 18:12:19

我正在使用c#制作一个。net类库(DLL),它将被广泛分发。我有一个抽象类叫Value,我想让它有一个抽象的double属性也叫Value,即

public abstract class Value {
    // Only accessible by subclasses within the project.
    internal Value() {}
    public abstract double Value {
        get;
    }
}

但是c#编译器不允许这样做——我得到的消息是"成员名不能与其封闭类型相同",如这里所讨论的。

我知道最简单的事情就是改变属性的名字或者类的名字…但我真的希望名字是这样的,我很乐意实现一个丑陋的hack来实现它。只要它能从使用这个DLL的外部代码中正常工作。

不像c#, VB。Net 允许我定义一个与类同名的属性,所以我目前正在研究将我的c#项目与定义Value类(及其Value属性)的VB项目合并为一个DLL。这似乎不像我希望的那么简单。

另一个选择是在VB中重写整个项目…不是很吸引人,但如果有必要我会考虑的。比起VB,我更喜欢c#。Net,但我的首要任务是得到我想要的方式构建DLL。

我想知道可能有什么其他的选择。有什么好的破解方法吗?

编辑:从下面的评论中可以清楚地看出,相当多的人不认为"Value"这个名字是一个类的…有人能解释一下为什么这么糟糕吗?我知道这不是一个很好的描述,但我认为它很适合我的项目背景。是因为它是c#中用于属性设置的关键字吗?

我可以用什么hack来定义一个与类同名的c#属性?

你不能直接这么做。但是,您可以考虑:

  • 实现带有Value成员的接口,并使用显式接口实现(尽管调用者可以使用该接口)
  • 在类中重命名它,并使用扩展方法来暴露Value()方法,因此obj.Value()工作
  • 在类中重命名它,但在子类
  • 中将其暴露为Value

丑陋的黑客:

public abstract class ValueBase {
    public abstract double Value { get; }
    internal ValueBase() {}
}
public abstract class Value : ValueBase {
    internal Value() {}
}
public sealed class ValueReal : Value {
    public override double Value { get { return 123; } }
}

如果您的类是双精度类型的代表(除了一些额外的元数据),您可以选择转换操作符:

public abstract class Value
{
    protected abstract double GetValue();
    public static explicit operator double (Value value)
    {
        return value.GetValue();
    }
}
然后您的客户端代码可以访问元数据或将类型为Value的实例强制转换为double。根据元数据和使用情况,可以隐式转换,这样就不必进行显式强制转换,还可以定义从doubleValue的转换。

System.Xml.Linq程序集也使用了类似的方法,例如,XElement可以被强制转换为任何基本类型,作为访问其"值"的一种手段。

正如其他人所说,这在c#中是不可能的。

其他人批评Value这个名字作为一个类,虽然我同意它可能过于通用,但我可以看到它可能有意义的情况。

记住,如果Value是一个抽象类,也许ValueBase可能是一个体面的,一致的名称?很多。net框架(尤其是WPF)都使用XxxBase

另一个可以考虑的选项是在类名前加上项目名,如FooValue。

Value是一个糟糕的类名。它非常模糊,所以它无法描述Value代表什么,并且它与保留词"Value"相冲突。你会发现自己在使用value = Value.Value,想知道为什么你的代码没有意义,并最终试图修复一个可怕的错误,这是使用"value"而不是value或value或_value或this.value的直接结果。当你必须存储另一种任意数字时会发生什么?你会把它命名为Value2吗?

用更具体和有意义的名称命名类,问题将不再存在。不要修复症状 -修复原因

即使你只把它重命名为"DataValue"或"MySystemValue",你也会为自己做一个伟大的服务。

遵从大众意见,我决定将我的Value类重命名为DataValue。我对这个名字很满意,这意味着我不需要任何黑客来拥有名为Value的属性。所以非常感谢大家的反馈。

但是,尽管有有用的答案,我仍然认为这个问题没有得到理想的回答。所提出的解决方案都不能完全满足要求,或者至少不能没有副作用,例如要求使用多余的接口或公共类。我可能应该在我的问题中更清楚地表示,我非常乐意考虑涉及不安全代码的黑客,或修改中间语言或诸如此类的黑客,因为我的首要任务是按照我想要的方式获得DLL的公共API,而不管它的源代码中可能隐藏着什么混乱的黑客。

所以这是我能想到的最好的解决方案。实际上我自己并没有这样做(现在不需要了,我为类使用了不同的名称),但是我没有任何理由怀疑它不会工作:

  1. 在包含c#类库项目的解决方案中,添加一个新的VB类库项目。

  2. 在VB项目中,创建类(Value在我原来的例子)。在VB中添加与类同名的属性是没有问题的。

  3. 如果你的VB类有c#代码需要引用的内部方法,在你的VB类中使用InternalsVisibleTo引用c#程序集。

  4. 你现在应该能够从你的c#项目中引用你的VB类。但是,当您构建解决方案时,您将获得两个独立的dll:一个用于c#代码,另一个用于VB代码。看起来ILMerge工具可以非常直接地将两个dll合并为一个(只需从命令行调用一次)。

所以最后你应该有一个单一的DLL,其中包含具有相同名称的属性的类,以及c#项目中的所有代码。其他使用DLL的项目(c#, VB或任何其他。net语言)不应该看到你的hack -他们所看到的是一个一致的API,没有多余的公共类或接口。