Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# if语句中的赋值_C#_Casting_If Statement - Fatal编程技术网

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完成。)
  • 与“惯用while”没有什么不同。(只是不要得意忘形:以一致的形式和简单的方式保持条件。)
  • 要将
    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