C# 泛型类型 typedef/alias 和 InvalidCastException

C# generic types typedef/alias and InvalidCastException

使用泛型类型的泛型变得可读性差,所以我想创建一个更短的别名。例如:

1) 在这种情况下通过 subclassing.

public class Parameters : Dictionary<string, string> {};

对我来说这真的只是一个别名,所以在某些时候我想做:

var myDictionary = new Dictionary<string, string>;
// some operations on myDictionary
Parameters parameters = (Parameters)myDictionary;

我得到一个 InvalidCastOperation,我想是因为我想从 baseclass 转换为继承的 class(我的 "trick" 得到一个别名)。

不幸的是,这也不允许挽救一天:

public class Parameters : Dictionary<string, string>
{
    public static implicit operator Parameters(Dictionary<string, string> dict)
    {
        Parameters res = new Parameters();
        foreach (var parameter in dict)
            res.Add(parameter.Key, parameter.Value);
        return res;
    }
};

不编译。所以这看起来像死胡同。

我也许可以编写自己的方法,我必须显式调用该方法,但隐式转换会好得多。

2) 或者,我可以在文件级别进行 delcare:

using Parameters = System.Collections.Generic.Dictionary<string, string>;

这有缺点,我需要为我想在其中使用类型(或使用完整语法)的每个文件声明它。

如何获得具有隐式转换且只需要声明一次的别名?

edit/add
为了更好地理解,这是实际代码。

public delegate Parameters UrlHandler(Parameters jsonParameters);
public class RequestHandlers : Dictionary<string, UrlHandler> { };
public class Parameters : Dictionary<string, string> { };

当我在 2 个参数之间执行 Linq 联合时,问题就来了,这导致了字典。

在正常情况下,我不认为使用别名是一种好的做法。我相信它会降低代码的可读性。但是,如果您认为在您的特定情况下它会使代码更具可读性, 如果您认为 Parameters 可能成为不仅仅是字典的东西,您可以继承自 Dictionary<string,string> 并使用其复制构造函数:

public class Parameters : Dictionary<string, string>
{
    public Parameters(IDictionary<string, string> dict) : base(dict)
    {
    }
};

这将允许您这样做:

var myDictionary = new Dictionary<string, string>();

Parameters parameters = new Parameters(myDictionary);

还有这个:

Dictionary<string, string> dictionary = parameters;

您太依赖老派的 C 了。在 C 中,别名就是名称的快捷方式。当然,也许这可以让您省去很多按键操作,但现在这几乎不值得,尤其是在具有 IntelliSense 等功能的情况下。

与其只是给相同的类型一个不同的名称,不如创建您自己的类型,它只公开您的用例所需的任何内容。隐藏和抽象,而不仅仅是别名。

例如,您有 Parameters。您真的想要 Dictionary<string, string> 的所有属性和方法吗?您真的要允许来回隐式转换吗?

有很多解决方案更适合现代编程。但是您需要考虑您真正想要的是什么 - 意味着 表示 Parameters 的类型是什么?也许你想从某个地方传递一组参数,在一个点创建(例如从配置)并且只在其他地方读取?只需创建您自己的类型,并公开您真正想要的接口:

public class Parameters
{
  private readonly IDictionary<string, string> _parameters;

  public Parameters(IDictionary<string, string> parameters)
  {
    _parameters = parameters;
  }

  public string this[string key]
  {
    get { return _parameters[key]; }
  }
}

现在您只公开真正重要的接口。你需要一种方法来遍历参数吗?只需实施 IEnumerable<KeyValuePair<string, string>>.

真的需要字典吗?然后忘记使用 Dictionary<string, string> 的相当具体的 class,而是使用接口 IDictionary<string, string> - 这是你的 Parameters class 可以轻松实现的东西(也许只是委托给基础字典,具体取决于您的要求)。现在您可以从字典创建一个新的 Parameters...而 Parameters 本身 仍然是 一个字典,并且可以在任何其他 IDictionary<string, string> 可以使用的地方使用, 无需将其重铸为 Dictionary<string, string> - 你为什么要这样做呢?

考虑一下您的转换运算符尝试中的错误消息 - "User-defined conversions to or from a base class are not allowed"。您是否考虑过如果 没有 导致错误会发生什么情况?您会破坏所有继承和接口的工作方式 - 所以您的类型是 Dictionary<string, string>,但不是真的吗?如果你对 Dictionary<string, string> 进行隐式转换,它会制作一个副本,但如果你进行显式转换,它仍然是同一个实例?子类型总是可以转换为其父类型 - 这就是基于 class 的 OOP 的全部要点:)

拥抱 OOP。或者 FP,C# 也支持它。但是在 C# 中坚持 C 风格的编程是行不通的,你只会给每个人带来很多痛苦:)