Programing

if 문의 할당

lottogame 2020. 6. 27. 10:58
반응형

if 문의 할당


클래스 Animal와 하위 클래스가 Dog있습니다. 나는 종종 다음 줄을 코딩하는 것을 발견했다.

if (animal is Dog)
{
    Dog dog = animal as Dog;    
    dog.Name;    
    ... 
}

변수의 경우 Animal animal;.

다음과 같은 것을 작성할 수있는 구문이 있습니까?

if (Dog dog = animal as Dog)
{    
    dog.Name;    
    ... 
}

아래 답변은 몇 년 전에 작성되었으며 시간이 지남에 따라 업데이트되었습니다. C # 7부터 패턴 일치를 사용할 수 있습니다.

if (animal is Dog dog)
{
    // Use dog here
}

주의 dog애프터 범위에 여전히 if문,하지만 확실히 할당되지 않습니다.


아닙니다. 이것을 작성하는 것이 관용적입니다.

Dog dog = animal as Dog;
if (dog != null)
{
    // Use dog
}

"다음에 if"가 거의 항상 이런 식으로 사용 된다는 것을 감안할 때 , 한 번에 두 부분을 모두 수행하는 연산자가있는 것이 더 합리적 일 수 있습니다. 패턴 일치 제안 이 구현 된 경우 현재 C # 6에는 없지만 C # 7에 포함될 수 있습니다 .

문제는 명령문 1 의 조건 부분에서 변수를 선언 할 수 없다는 것 입니다. 내가 생각할 수있는 가장 가까운 접근법은 다음과 같습니다.if

// EVIL EVIL EVIL. DO NOT USE.
for (Dog dog = animal as Dog; dog != null; dog = null)
{
    ...
}

그것은 단지 불쾌합니다 ... (방금 시도했지만 작동합니다. 그러나 제발, 제발, 제발 그렇게하지 마십시오. 아, 물론 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);
    }
}

그런 다음 전화하십시오.

animal.AsIf<Dog>(dog => {
    // Use dog in here
});

또는 두 가지를 결합 할 수 있습니다.

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);
    }
}

for 루프보다 깔끔한 방식으로 람다식이없는 확장 메서드를 사용할 수도 있습니다.

public static IEnumerable<T> AsOrEmpty(this object value)
{
    T t = value as T;
    if (t != null)
    {
        yield return t;
    }
}

그때:

foreach (Dog dog in animal.AsOrEmpty<Dog>())
{
    // use dog
}

1 드물지만 문장에 값을 할당 할 수 있습니다 if. 그러나 변수 선언과는 다릅니다. 데이터 스트림을 읽을 때 가끔 그렇게하는 것은 끔찍한이 아닙니다 while. 예를 들면 다음과 같습니다.

string line;
while ((line = reader.ReadLine()) != null)
{
    ...
}

요즘에는 일반적으로 래퍼를 사용하여 사용할 수 foreach (string line in ...)있지만 위의 내용을 꽤 관용적 인 패턴으로 생각합니다. 그것은이다 일반적으로 조건 내에서 부작용을 가지고 좋은 아니지만, 대안은 일반적으로 코드 중복을 포함, 당신은이 패턴을 알고있을 때 그것을 바로 얻을 쉽습니다.


경우 as에 실패, 그것은 반환합니다 null.

Dog dog = animal as Dog;

if (dog != null)
{
    // do stuff
}

변수가 이미 존재하는 한 변수에 값을 지정할 있습니다 . 문제가있는 경우 나중에 같은 방법으로 해당 변수 이름을 나중에 다시 사용할 수 있도록 변수의 범위를 지정할 수도 있습니다.

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();
                // ...
            }
        }
    }
}

가정

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");
    }
}

출력을 얻는다 :

Name is now Scopey
Flying

테스트에서 변수 할당 패턴은 또한 스트림에서 바이트 블록을 읽을 때 사용됩니다.

int bytesRead = 0;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0) 
{
    // ...
}

그러나 위에서 사용 된 변수 범위 패턴은 특히 일반적인 코드 패턴이 아니며, 모든 곳에서 사용되는 것을 보았을 때 리팩토링 할 방법을 찾고있었습니다.


다음과 같은 것을 작성할 수있는 구문이 있습니까?

if (Dog dog = animal as Dog) { ... dog ... }

?

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 ...

보다 일반적으로, 제안 된 특징은 로컬 변수 선언이 표현식으로 사용될 수 있다는 것 입니다. if구문은보다 일반적인 기능의 좋은 결과 일뿐입니다.


내가 자주 쓰고 사용하는 확장 방법 중 하나는 *

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);

그리고 개의 name이름입니다 (개인 경우). 그렇지 않으면 null입니다.

* 이것이 성능 적인지 모르겠습니다. 프로파일 링에서 병목 현상이 발생하지 않았습니다.


여기서 곡식에 반대하지만 처음에 잘못하고있을 수 있습니다. 객체의 유형을 확인하는 것은 거의 항상 코드 냄새입니다. 귀하의 예에서 모든 동물이 이름을 가지고 있지는 않습니까? 그런 다음 개인 지 여부를 확인하지 않고 Animal.name을 호출하십시오.

또는 Animal의 구체적인 유형에 따라 다르게 작동하는 Animal 메서드를 호출하도록 메서드를 반전시킵니다. 참조 : 다형성.


짧은 진술

var dog = animal as Dog
if(dog != null) dog.Name ...;

다음은 기본 클래스 수정에 의존하는 더티 코드 (Jon 's와 같은 더티가 아님)입니다. 나는 그것이 요점을 누락시키면서 의도를 포착한다고 생각합니다.

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();
    }
}

여러 개의 if-if를 하나씩 차례로 수행해야하는 경우 (다형성을 사용하는 것은 옵션이 아님) SwitchOnType 구문을 사용하십시오 .


C #의 대입 연산자가 유효한 식이므로 문제 (구문 사용)가 대입과 관련 없습니다 . 오히려 선언이 진술이므로 원하는 선언이 있습니다.

그런 코드를 작성 해야하는 경우 때로는 더 큰 컨텍스트에 따라 다음과 같이 코드를 작성합니다.

Dog dog;
if ((dog = animal as Dog) != null) {
    // use dog
}

위의 구문 (요청한 구문에 가까운)에는 다음과 같은 장점이 있습니다.

  1. dog 외부 에서 사용하면 if다른 곳에 값이 할당되지 않으므로 컴파일 오류가 발생합니다. (즉, 다른 곳에 할당 하지 마십시오dog .)
  2. 이 접근법은 if/else if/...다음과 같이 훌륭하게 확장 될 수 있습니다 ( as적절한 지점을 선택하는 데 필요한만큼만 있습니다. 필요할 때이 양식으로 작성 하는 큰 경우 입니다).
  3. 의 중복을 피하십시오 is/as. (그러나 Dog dog = ...양식으로 도 수행됩니다 .)
  4. "아이디 오마 틱 동안"과 다르지 않습니다. (단지 수행하지 마십시오. 조건을 일관된 형태로 단순하게 유지하십시오.)

dog다른 세계와 진정으로 분리하기 위해 새로운 블록을 사용할 수 있습니다.

{
  Dog dog = ...; // or assign in `if` as per above
}
Bite(dog); // oops! can't access dog from above

행복한 코딩.


확장 방법을 가진 또 다른 EVIL 솔루션 :)

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
}

if 문은 허용하지 않지만 for 루프는 허용합니다.

예 :

for (Dog dog = animal as Dog; dog != null; dog = null)
{
    dog.Name;    
    ... 
}

작동 방식이 즉시 명확하지 않은 경우 프로세스에 대한 단계별 설명이 있습니다.

  • 가변 개는 유형 개로 작성되며 Dog에 캐스트되는 가변 동물이 지정됩니다.
  • 할당이 실패하면 dog가 널 (null)이므로 for 루프의 내용이 즉시 중단되므로 for 루프의 내용이 실행되지 않습니다.
  • 할당이 성공하면 for 루프가
    반복을 통해 실행됩니다 .
  • At the end of the iteration, the dog variable is assigned a value of null, which breaks out of the for loop.

using(Dog dog = animal as Dog)
{
    if(dog != null)
    {
        dog.Name;    
        ... 

    }

}

IDK if this helps anybody but you can always try to use a TryParse to assign your variable. Here is an example:

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;
    }

The total variable would be declared before your if statement.


I have just inlined the if statement to create a line of code that looks like what you are interested in. It just helps compress the code some and I found it to be more readable especially when nesting assignments:

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);
    }
 }

you can use something like that

//Declare variable bool temp= false;

 if (previousRows.Count > 0 || (temp= GetAnyThing()))
                                    {
                                    }

참고URL : https://stackoverflow.com/questions/7113347/assignment-in-an-if-statement

반응형