클래스 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 ...;