[C#] 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 ...;