mic*_*ael 133 c# casting if-statement
我有一个类Animal及其子类Dog.我经常发现自己编写以下代码:
if (animal is Dog)
{
Dog dog = animal as Dog;
dog.Name;
...
}
Run Code Online (Sandbox Code Playgroud)
对于变量Animal animal;.
是否有一些语法允许我写如下:
if (Dog dog = animal as Dog)
{
dog.Name;
...
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 302
下面的答案是几年前写的,随着时间的推移而更新.从C#7开始,您可以使用模式匹配:
if (animal is Dog dog)
{
// Use dog here
}
Run Code Online (Sandbox Code Playgroud)
请注意,dog该if语句后仍在范围内,但未明确分配.
不,没有.写这个是更惯用的:
Dog dog = animal as Dog;
if (dog != null)
{
// Use dog
}
Run Code Online (Sandbox Code Playgroud)
鉴于"as if by if"几乎总是以这种方式使用,因此有一个操作员可以一次性执行这两个部分更有意义.如果实现了模式匹配提议,这目前不在C#6中,但可能是C#7的一部分.
问题是你不能在语句1的条件部分声明变量.我能想到的最接近的方法是:if
// EVIL EVIL EVIL. DO NOT USE.
for (Dog dog = animal as Dog; dog != null; dog = null)
{
...
}
Run Code Online (Sandbox Code Playgroud)
这只是令人讨厌的 ......(我刚试过它,它确实有用.但请不要这样做.哦,你当然可以宣布dog使用var.)
当然你可以写一个扩展方法:
public static void AsIf<T>(this object value, Action<T> action) where T : class
{
T t = value as T;
if (t != null)
{
action(t);
}
}
Run Code Online (Sandbox Code Playgroud)
然后用:
animal.AsIf<Dog>(dog => {
// Use dog in here
});
Run Code Online (Sandbox Code Playgroud)
或者,您可以将两者结合起来:
public static void AsIf<T>(this object value, Action<T> action) where T : class
{
// EVIL EVIL EVIL
for (var t = value as T; t != null; t = null)
{
action(t);
}
}
Run Code Online (Sandbox Code Playgroud)
您还可以使用没有lambda表达式的扩展方法,比for循环更简洁:
public static IEnumerable<T> AsOrEmpty(this object value)
{
T t = value as T;
if (t != null)
{
yield return t;
}
}
Run Code Online (Sandbox Code Playgroud)
然后:
foreach (Dog dog in animal.AsOrEmpty<Dog>())
{
// use dog
}
Run Code Online (Sandbox Code Playgroud)
1您可以在语句中指定值if,但我很少这样做.这与声明变量不同.虽然在阅读数据流时,我做这件事并不是特别不寻常while.例如:
string line;
while ((line = reader.ReadLine()) != null)
{
...
}
Run Code Online (Sandbox Code Playgroud)
这些天我通常更喜欢使用一个让我使用的包装,foreach (string line in ...)但我认为上面是一个非常惯用的模式.这通常不是很好,有一个条件中的副作用,但替代品通常涉及重复代码,当你知道这种模式很容易得到的权利.
Pla*_*ure 48
如果as失败,则返回null.
Dog dog = animal as Dog;
if (dog != null)
{
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
Han*_*man 12
您可以将值赋给变量,只要变量已经存在.您还可以对变量进行范围调整,以允许稍后在同一方法中再次使用该变量名称(如果这是一个问题).
public void Test()
{
var animals = new Animal[] { new Dog(), new Duck() };
foreach (var animal in animals)
{
{ // <-- scopes the existence of critter to this block
Dog critter;
if (null != (critter = animal as Dog))
{
critter.Name = "Scopey";
// ...
}
}
{
Duck critter;
if (null != (critter = animal as Duck))
{
critter.Fly();
// ...
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
假设
public class Animal
{
}
public class Dog : Animal
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
Console.WriteLine("Name is now " + _name);
}
}
}
public class Duck : Animal
{
public void Fly()
{
Console.WriteLine("Flying");
}
}
Run Code Online (Sandbox Code Playgroud)
得到输出:
Name is now Scopey
Flying
Run Code Online (Sandbox Code Playgroud)
当从流中读取字节块时,也会使用测试中的变量赋值模式,例如:
int bytesRead = 0;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
然而,上面使用的变量范围的模式并不是一个特别常见的代码模式,如果我看到它被遍地使用,我会寻找一种方法来重构它.
Eri*_*ert 11
是否有一些语法允许我写如下:
if (Dog dog = animal as Dog) { ... dog ... }
Run Code Online (Sandbox Code Playgroud)
?
可能会出现在C#6.0中.此功能称为"声明表达式".看到
https://roslyn.codeplex.com/discussions/565640
详情.
建议的语法是:
if ((var i = o as int?) != null) { … i … }
else if ((var s = o as string) != null) { … s … }
else if ...
Run Code Online (Sandbox Code Playgroud)
更一般地,所提出的特征是局部变量声明可以用作表达式.这种if语法只是更通用功能的一个很好的结果.
我发现自己经常编写和使用的一种扩展方法是
public static TResult IfNotNull<T,TResult>(this T obj, Func<T,TResult> func)
{
if(obj != null)
{
return func(obj);
}
return default(TResult);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下可以使用哪种方式
string name = (animal as Dog).IfNotNull(x => x.Name);
Run Code Online (Sandbox Code Playgroud)
然后name是狗的名字(如果是狗),否则为空.
*我不知道这是否具有高效性.它从未成为分析的瓶颈.
在这里反对谷物,但也许你首先做错了.检查对象的类型几乎总是代码味道.在您的示例中,并非所有动物都有姓名吗?然后只需调用Animal.name,而不检查它是否是狗.
或者,反转方法,以便在Animal上调用一个方法,该方法根据Animal的具体类型执行不同的操作.另见:多态性.