C# if语句中的赋值
我有一个类C# if语句中的赋值,c#,casting,if-statement,C#,Casting,If Statement,我有一个类Animal,以及它的子类Dog。 我经常发现自己在编写以下代码: if (animal is Dog) { Dog dog = animal as Dog; dog.Name; ... } 对于变量动物 是否有一些语法允许我编写以下内容: if (Dog dog = animal as Dog) { dog.Name; ... } 如果as失败,则返回null Dog dog = animal as Do
Animal
,以及它的子类Dog
。
我经常发现自己在编写以下代码:
if (animal is Dog)
{
Dog dog = animal as Dog;
dog.Name;
...
}
对于变量<代码>动物代码>
是否有一些语法允许我编写以下内容:
if (Dog dog = animal as Dog)
{
dog.Name;
...
}
如果
as
失败,则返回null
Dog dog = animal as Dog;
if (dog != null)
{
// do stuff
}
下面的答案是多年前写的,随着时间的推移不断更新。从C#7开始,您可以使用模式匹配:
if (animal is Dog dog)
{
// Use dog here
}
请注意,dog
仍在if
语句之后的范围内,但没有明确指定
不,没有。不过,这样写更贴切:
Dog dog = animal as Dog;
if (dog != null)
{
// Use dog
}
考虑到“as following by if”几乎总是这样使用,因此,如果有一个操作符一次完成这两个部分,可能会更有意义。这目前不在C#6中,但如果实现了,则可能是C#7的一部分
问题是您不能在if
语句1的条件部分声明变量。我能想到的最接近的方法是:
// EVIL EVIL EVIL. DO NOT USE.
for (Dog dog = animal as Dog; dog != null; dog = null)
{
...
}
那太恶心了。。。(我刚刚试过,它确实有效。但是请不要这样做。哦,当然,你可以使用var
声明dog
)
当然,您可以编写一个扩展方法:
public static void AsIf<T>(this object value, Action<T> action) where T : class
{
T t = value as T;
if (t != null)
{
action(t);
}
}
这些天来,我通常更喜欢使用包装器,它允许我使用foreach(stringline in…
),但我认为上面的模式非常惯用。在一种情况下产生副作用通常是不好的,但替代方案通常涉及代码复制,当您知道这种模式时,很容易纠正。Shorter语句
var dog = animal as Dog
if(dog != null) dog.Name ...;
只要变量已经存在,就可以为变量赋值。如果出现问题,还可以对变量进行范围限定,以允许稍后在同一方法中再次使用该变量名
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();
// ...
}
}
}
}
获取输出:
Name is now Scopey
Flying
从流中读取字节块时,也会使用测试中的变量分配模式,例如:
string line;
while ((line = reader.ReadLine()) != null)
{
...
}
int bytesRead = 0;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
// ...
}
然而,上面使用的变量作用域模式并不是一种特别常见的代码模式,如果我看到它被广泛使用,我会寻找一种方法来重构它。这里有一些额外的脏代码(虽然没有Jon的脏:-)依赖于修改基类。我认为它抓住了意图,但可能没有抓住要点:
class Animal
{
public Animal() { Name = "animal"; }
public List<Animal> IfIs<T>()
{
if(this is T)
return new List<Animal>{this};
else
return new List<Animal>();
}
public string Name;
}
class Dog : Animal
{
public Dog() { Name = "dog"; }
public string Bark { get { return "ruff"; } }
}
class Program
{
static void Main(string[] args)
{
var animal = new Animal();
foreach(Dog dog in animal.IfIs<Dog>())
{
Console.WriteLine(dog.Name);
Console.WriteLine(dog.Bark);
}
Console.ReadLine();
}
}
类动物
{
公共动物(){Name=“Animal”;}
公开名单
{
如果(这是T)
返回新列表{this};
其他的
返回新列表();
}
公共字符串名称;
}
狗类:动物
{
公共狗(){Name=“Dog”;}
公共字符串Bark{get{返回“ruff”;}
}
班级计划
{
静态void Main(字符串[]参数)
{
var动物=新动物();
foreach(Dog-Dog-in-animal.IfIs())
{
Console.WriteLine(dog.Name);
控制台。书写线(狗吠);
}
Console.ReadLine();
}
}
我发现自己经常编写和使用的扩展方法之一是
public static TResult IfNotNull<T,TResult>(this T obj, Func<T,TResult> func)
{
if(obj != null)
{
return func(obj);
}
return default(TResult);
}
然后name
是狗的名字(如果是狗的话),否则为空
*我不知道这是否有效。它从来没有成为分析的瓶颈。 如果你必须做多个,比如IFS一点零一分(并且使用多态性不是一个选项),考虑使用一个构造。 在这里逆来顺受,但也许你一开始就做错了。检查对象的类型几乎总是一种代码味道。在你的例子中,不是所有的动物都有名字吗?然后就叫Animal.name,不检查它是不是狗 或者,颠倒方法,以便调用动物上的方法,该方法根据动物的具体类型执行不同的操作。另请参见:多态性。语法问题不在于赋值,因为C#中的赋值运算符是有效的表达式。相反,它与所需的声明是一致的,因为声明是语句 如果我必须这样编写代码,我有时会(取决于更大的上下文)这样编写代码:
Dog dog;
if ((dog = animal as Dog) != null) {
// use dog
}
上述语法有其优点(与请求的语法接近),因为:
if
之外使用dog
将导致编译错误,因为它没有在别处赋值。(也就是说,不要将狗分配到其他地方。)
if/else if/…
(选择合适的分支所需的数量与数量相同;在这种情况下,我必须以这种形式编写分支。)
is/as
。(但也可以使用Dog-Dog=…
form完成。)dog
与世界其他地方真正隔离,可以使用一个新块:
{
Dog dog = ...; // or assign in `if` as per above
}
Bite(dog); // oops! can't access dog from above
快乐编码
是否有一些语法允许我编写以下内容:
if (Dog dog = animal as Dog)
{
dog.Name;
...
}
?
在C#6.0中可能会出现这种情况。此功能称为“声明表达式”。看
详情请参阅
建议的语法是:
if ((var i = o as int?) != null) { … i … }
else if ((var s = o as string) != null) { … s … }
else if ...
更一般地说,建议的特性是可以使用局部变量声明作为表达式。这
if
语法只是更通用功能的一个好结果。另一个带有扩展方法的邪恶解决方案:)
if语句不允许这样做,但for循环将允许这样做 e、 g 如果它的工作方式不是很明显,那么下面是对该过程的逐步说明:
- 变量dog被创建为类型dog,并分配给变量animal 那是给狗的
- 如果分配失败,则dog为null,这将阻止内容 由于for循环立即中断,因此无法运行 的李>
- 如果赋值成功,则for循环将通过t运行
public static TResult IfNotNull<T,TResult>(this T obj, Func<T,TResult> func) { if(obj != null) { return func(obj); } return default(TResult); }
string name = (animal as Dog).IfNotNull(x => x.Name);
Dog dog; if ((dog = animal as Dog) != null) { // use dog }
{ Dog dog = ...; // or assign in `if` as per above } Bite(dog); // oops! can't access dog from above
if (Dog dog = animal as Dog) { ... dog ... }
if ((var i = o as int?) != null) { … i … } else if ((var s = o as string) != null) { … s … } else if ...
public class Tester { public static void Test() { Animal a = new Animal(); //nothing is printed foreach (Dog d in a.Each<Dog>()) { Console.WriteLine(d.Name); } Dog dd = new Dog(); //dog ID is printed foreach (Dog dog in dd.Each<Dog>()) { Console.WriteLine(dog.ID); } } } public class Animal { public Animal() { Console.WriteLine("Animal constructued:" + this.ID); } private string _id { get; set; } public string ID { get { return _id ?? (_id = Guid.NewGuid().ToString());} } public bool IsAlive { get; set; } } public class Dog : Animal { public Dog() : base() { } public string Name { get; set; } } public static class ObjectExtensions { public static IEnumerable<T> Each<T>(this object Source) where T : class { T t = Source as T; if (t == null) yield break; yield return t; } }
Dog dog = animal as Dog; if (dog != null) { // do stuff }
for (Dog dog = animal as Dog; dog != null; dog = null) { dog.Name; ... }
using(Dog dog = animal as Dog) { if(dog != null) { dog.Name; ... } }
if (int.TryParse(Add(Value1, Value2).ToString(), out total)) { Console.WriteLine("I was able to parse your value to: " + total); } else { Console.WriteLine("Couldn't Parse Value"); } Console.ReadLine(); } static int Add(int value1, int value2) { return value1 + value2; }
var dog = animal as Dog; if (dog != null) { Console.WriteLine("Parent Dog Name = " + dog.name); var purebred = dog.Puppy as Purebred; if (purebred != null) { Console.WriteLine("Purebred Puppy Name = " + purebred.Name); } var mutt = dog.Puppy as Mongrel; if (mutt != null) { Console.WriteLine("Mongrel Puppy Name = " + mutt.Name); } }
if (previousRows.Count > 0 || (temp= GetAnyThing())) { }
/// <summary> /// IAble exists solely to give ALL other Interfaces that inherit IAble the TryAs() extension method /// </summary> public interface IAble { } public static class IAbleExtension { /// <summary> /// Attempt to cast as T returning true and out-ing the cast if successful, otherwise returning false and out-ing null /// </summary> /// <typeparam name="T"></typeparam> /// <param name="able"></param> /// <param name="result"></param> /// <returns></returns> public static bool TryAs<T>(this IAble able, out T result) where T : class { if (able is T) { result = able as T; return true; } else { result = null; return false; } } /// <summary> /// Attempt to cast as T returning true and out-ing the cast if successful, otherwise returning false and out-ing null /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj"></param> /// <param name="result"></param> /// <returns></returns> public static bool TryAs<T>(this UnityEngine.Object obj, out T result) where T : class { if (obj is T) { result = obj as T; return true; } else { result = null; return false; } } }
if (animal.TryAs(out Dog dog)) { //Do Dog stuff here because animal is a Dog } else { //Cast failed! animal is not a dog }
Animal animal; if (animal as Dog is not null and Dog dog) { //You can get here only if animal is of type Dog and you can use dog variable only //in this scope }
animal is Dog ? (Dog)(animal) : (Dog)null