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 风格的编程是行不通的,你只会给每个人带来很多痛苦:)
使用泛型类型的泛型变得可读性差,所以我想创建一个更短的别名。例如:
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 风格的编程是行不通的,你只会给每个人带来很多痛苦:)