if 语句中的赋值

发布于 2024-11-30 10:56:57 字数 342 浏览 1 评论 0原文

我有一个类 Animal 及其子类 Dog。 我经常发现自己编写以下几行代码:

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

对于变量Animalanimal;

是否有某种语法允许我编写类似以下内容的语法:

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

I have a class Animal, and its subclass Dog.
I often find myself coding the following lines:

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

For the variable Animal animal;.

Is there some syntax that allows me to write something like:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(21

夏末 2024-12-07 10:56:57

下面的答案是几年前写的,并随着时间的推移而更新。从 C# 7 开始,您可以使用模式匹配:

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

请注意,dog 仍在 if 语句之后的范围内,但并未明确分配。


不,没有。不过,这样写更符合习惯用法:

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

鉴于“as 随后是 if”几乎总是以这种方式使用,因此有一个运算符一次性执行这两个部分可能更有意义。目前 C# 6 中没有此功能,但如果 模式匹配提案<,则可能是 C# 7 的一部分/a> 已实施。

问题是您无法在 if 语句1的条件部分声明变量。我能想到的最接近的方法是:

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

That's just nasty...(我刚刚尝试过,它确实有效。但是请不要这样做。哦,还有你当然可以使用 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);
    }
}

然后用以下方式调用它:

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

您还可以使用没有 lambda 表达式的扩展方法比 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 语句中赋值值,尽管我很少这样做。但这与声明变量不同。不过,在读取数据流时,在一段时间内执行此操作对我来说并不罕见。例如:

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

这些天我通常更喜欢使用一个包装器,它允许我使用 foreach (string line in ...) 但我认为上面是一个非常惯用的模式。在一个条件中产生副作用通常不太好,但替代方案通常涉及代码重复,当您知道这种模式时,就很容易做到正确。

The answer below was written years ago and updated over time. As of C# 7, you can use pattern matching:

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

Note that dog is still in scope after the if statement, but isn't definitely assigned.


No, there isn't. It's more idiomatic to write this though:

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

Given that "as followed by if" is almost always used this way, it might make more sense for there to be an operator which performs both parts in one go. This isn't currently in C# 6, but may be part of C# 7, if the pattern matching proposal is implemented.

The problem is that you can't declare a variable in the condition part of an if statement1. The closest approach I can think of is this:

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

That's just nasty... (I've just tried it, and it does work. But please, please don't do this. Oh, and you can declare dog using var of course.)

Of course you could write an extension method:

public static void AsIf<T>(this object value, Action<T> action) where T : class
{
    T t = value as T;
    if (t != null)
    {
        action(t);
    }
}

Then call it with:

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

Alternatively, you could combine the two:

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

You can also use an extension method without a lambda expression in a cleaner way than the for loop:

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

Then:

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

1 You can assign values in if statements, although I rarely do so. That's not the same as declaring variables though. It's not terribly unusual for me to do it in a while though when reading streams of data. For example:

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

These days I normally prefer to use a wrapper which lets me use foreach (string line in ...) but I view the above as a pretty idiomatic pattern. It's usually not nice to have side-effects within a condition, but the alternatives usually involve code duplication, and when you know this pattern it's easy to get right.

阪姬 2024-12-07 10:56:57

如果 as 失败,则返回 null

Dog dog = animal as Dog;

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

If as fails, it returns null.

Dog dog = animal as Dog;

if (dog != null)
{
    // do stuff
}
你又不是我 2024-12-07 10:56:57

只要变量已经存在,您就可以将值分配给该变量。您还可以设置变量的范围,以允许稍后在同一方法中再次使用该变量名称(如果这是一个问题)。

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

上面使用的变量作用域模式,但是,不是一个特别常见的代码模式,如果我看到它被全部使用在这个地方我会寻找一种方法来重构它。

You can assign the value to the variable, as long as the variable already exists. You can also scope the variable to allow that variable name to be used again later in the same method, if that is a problem.

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

assuming

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

gets output:

Name is now Scopey
Flying

The pattern of variable assignment in the test is also used when reading byte blocks from streams, for example:

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

The pattern of variable scoping used above, however, is not a particularly common code pattern and if I saw it being used all over the place I'd be looking for a way to refactor it out.

白色秋天 2024-12-07 10:56:57

是否有一些语法可以让我编写如下内容:

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 语法只是更通用功能的一个很好的结果。

Is there some syntax that allows me to write something like:

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

?

There likely will be in C# 6.0. This feature is called "declaration expressions". See

https://roslyn.codeplex.com/discussions/565640

for details.

The proposed syntax is:

if ((var i = o as int?) != null) { … i … }
else if ((var s = o as string) != null) { … s … }
else if ...

More generally, the proposed feature is that a local variable declaration may be used as an expression. This if syntax is just a nice consequence of the more general feature.

春花秋月 2024-12-07 10:56:57

我发现自己经常编写和使用的扩展方法之一* 是

public static TResult IfNotNull<T,TResult>(this T obj, Func<T,TResult> func)
{
    if(obj != null)
    {
        return func(obj);
    }
    return default(TResult);
}

Which 可以在这种情况下使用,

string name = (animal as Dog).IfNotNull(x => x.Name);

然后 name 是狗的名字(如果它是狗),否则为 null。

*我不知道这是否有效。它从来没有成为分析的瓶颈。

One of the extension methods I find myself writing and using often* is

public static TResult IfNotNull<T,TResult>(this T obj, Func<T,TResult> func)
{
    if(obj != null)
    {
        return func(obj);
    }
    return default(TResult);
}

Which could be used in this situation as

string name = (animal as Dog).IfNotNull(x => x.Name);

And then name is the dog's name (if it is a dog), otherwise null.

*I have no idea if this is performant. It has never come up as a bottleneck in profiling.

我是男神闪亮亮 2024-12-07 10:56:57

这里违背了原则,但也许你一开始就做错了。检查对象的类型几乎总是代码味道。在你的例子中,不是所有的动物都有名字吗?然后只调用 Animal.name ,而不检查它是否是狗。

或者,反转该方法,以便调用 Animal 上的方法,该方法根据 Animal 的具体类型执行不同的操作。另请参见:多态性。

Going against the grain here, but maybe you're doing it wrong in the first place. Checking for an object's type is almost always a code smell. Don't all Animals, in your example, have a Name? Then just call Animal.name, without checking whether it's a dog or not.

Alternatively, invert the method so that you call a method on Animal that does something differently depending on the concrete type of the Animal. See also: Polymorphism.

烈酒灼喉 2024-12-07 10:56:57

较短的声明

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

Shorter Statement

var dog = animal as Dog
if(dog != null) dog.Name ...;
浅黛梨妆こ 2024-12-07 10:56:57

问题(语法方面)与赋值无关,因为 C# 中的赋值运算符是有效的表达式。相反,它是带有所需的声明,因为声明就是语句。

如果我必须编写这样的代码,我有时会(取决于更大的上下文)编写这样的代码:

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

上述语法有优点(接近请求的语法),因为:

  1. 使用 dog 外部 if 将导致编译错误,因为它没有在其他地方赋值。 (也就是说,不要在其他地方分配dog。)
  2. 这种方法也可以很好地扩展到if/else if/...(只有选择适当分支所需的as这是大情况,当我必须时,我会以这种形式编写它。)
  3. 避免重复是/作为。 (但也用Dog dog = ...形式完成。)
  4. 与“惯用的while”没有什么不同。 (只是不要得意忘形:保持条件的形式一致且简单。)

为了真正将 dog 与世界其他地方隔离,可以使用一个新块:

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

快乐编码。

The problem (with the syntax) is not with the assignment, as the assignment operator in C# is a valid expression. Rather, it is with the desired declaration as declarations are statements.

If I must write code like that I will sometimes (depending upon the larger context) write the code like this:

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

There are merits with the above syntax (which is close to the requested syntax) because:

  1. Using dog outside the if will result in a compile error as it is not assigned a value elsewhere. (That is, don't assign dog elsewhere.)
  2. This approach can also be expanded nicely to if/else if/... (There are only as many as as required to select an appropriate branch; this the big case where I write it in this form when I must.)
  3. Avoids duplication of is/as. (But also done with Dog dog = ... form.)
  4. Is no different than "idiomatic while". (Just don't get carried away: keep the conditional in a consistent form and and simple.)

To truly isolate dog from the rest of the world a new block can be used:

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

Happy coding.

彻夜缠绵 2024-12-07 10:56:57

在 C# 9.0 和 .NET 5.0 中,您可以使用 as 来编写它:

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
}

这是因为 if 语句中的 animal as Dog 产生与以下相同的结果:

animal is Dog ? (Dog)(animal) : (Dog)null

then is not null 部分检查上述语句的结果是否不为 null。仅当该语句为 true 时,它​​才会创建 Dog 类型的变量,该变量不能为 null。

此功能随模式组合器一起出现在 C# 9.0 中,您可以在此处阅读有关该功能的更多信息:
https:// learn.microsoft.com/pl-pl/dotnet/csharp/language-reference/proposals/csharp-9.0/patterns3#pattern-combinators

With C# 9.0 and .NET 5.0 you can write it using as like that:

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
}

It is because the animal as Dog in if statement produces the same result as:

animal is Dog ? (Dog)(animal) : (Dog)null

then is not null part checks if the result of above statement isn't null. Only if this statement is true it creates variable of type Dog dog, which can't be null.

This feature came to C# 9.0 with Pattern Combinators, you can read more about that right here:
https://learn.microsoft.com/pl-pl/dotnet/csharp/language-reference/proposals/csharp-9.0/patterns3#pattern-combinators

与往事干杯 2024-12-07 10:56:57

另一个迟到的条目:

if (animal is Dog dog) 
{ 
    dog.Name="Fido"; 
}
else if (animal is Cat cat)
{
    cat.Name="Bast";
}

Another late entry:

if (animal is Dog dog) 
{ 
    dog.Name="Fido"; 
}
else if (animal is Cat cat)
{
    cat.Name="Bast";
}
丘比特射中我 2024-12-07 10:56:57

这里有一些额外的脏代码(不过不像乔恩的那么脏:-))依赖于修改基类。我认为它抓住了意图,但可能没有抓住要点:

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

Here's some additional dirty code (not as dirty as Jon's, though :-)) dependent on modifying the base class. I think it captures the intent while perhaps missing the point:

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();
    }
}
我三岁 2024-12-07 10:56:57

如果您必须一个接一个地执行多个 if-if(并且使用多态性不是一种选择),请考虑使用 SwitchOnType 构造。

If you have to do multiple such as-ifs one after one (and using polymorphism is not an option), consider using a SwitchOnType construct.

迷荒 2024-12-07 10:56:57

使用 C# 7模式匹配您现在可以执行以下操作:

if (returnsString() is string msg) {
  Console.WriteLine(msg);
}

这个问题是十多年前提出的,所以几乎所有其他答案都已过时/错误

With C# 7's Pattern Matching you can now do things like:

if (returnsString() is string msg) {
  Console.WriteLine(msg);
}

This question was asked over 10 years ago now so almost all the other answers are outdated/wrong

甜`诱少女 2024-12-07 10:56:57

IDK 如果这对任何人都有帮助,但您始终可以尝试使用 TryParse 来分配变量。下面是一个示例:

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

total 变量将在 if 语句之前声明。

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.

心作怪 2024-12-07 10:56:57

你可以使用类似的东西

//声明变量
布尔温度=假;

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

you can use something like that

//Declare variable
bool temp= false;

 if (previousRows.Count > 0 || (temp= GetAnyThing()))
                                    {
                                    }
梦屿孤独相伴 2024-12-07 10:56:57

所有的小实验表明,我们可以在 if 语句中使用赋值

public static async Task Main(string[] args)
{
    bool f = false;
    if (f = Tru())
    {
        System.Diagnostics.Debug.WriteLine("True");
    }
    if (f = Tru(false))
    {
        System.Diagnostics.Debug.WriteLine("False");
    }
}

private static bool Tru(bool t = true) => t ? true : false;

在此处输入图像描述

至于任何潜在的副作用或“邪恶”,我想不出任何副作用,尽管我确信有人可以。欢迎评论!

Al little experimentation shows that we can use assignment in an if statement

public static async Task Main(string[] args)
{
    bool f = false;
    if (f = Tru())
    {
        System.Diagnostics.Debug.WriteLine("True");
    }
    if (f = Tru(false))
    {
        System.Diagnostics.Debug.WriteLine("False");
    }
}

private static bool Tru(bool t = true) => t ? true : false;

enter image description here

As far as any potential side effects or "Evil", I can't think of any, although I am sure somebody can. Comments welcome!

执笏见 2024-12-07 10:56:57

另一个带有扩展方法的邪恶解决方案:)

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
}

Another EVIL solution with extension methods :)

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

I personally prefer the clean way:

Dog dog = animal as Dog;

if (dog != null)
{
    // do stuff
}
悸初 2024-12-07 10:56:57

if 语句不允许这样做,但 for 循环可以。

例如,

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

如果它的工作方式不是很明显,那么这里是该过程的逐步说明:

  • 变量dog被创建为dog类型并分配了变量animal
    被投射到 Dog 上。
  • 如果分配失败,则dog为空,这会阻止内容
    for 循环停止运行,因为它立即被打破
    的。
  • 如果赋值成功,则 for 循环将运行
    迭代。
  • 在迭代结束时,dog 变量被赋值为
    null,它会跳出 for 循环。

An if statement won't allow that, but a for loop will.

e.g.

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

In case the way it works is not immediately obvious then here is a step by step explanation of the process:

  • Variable dog is created as type dog and assigned the variable animal
    that is cast to Dog.
  • If the assignment fails then dog is null, which prevents the contents
    of the for loop from running, because it is immediately broken out
    of.
  • If the assignment succeeds then the for loop runs through the
    iteration.
  • At the end of the iteration, the dog variable is assigned a value of
    null, which breaks out of the for loop.
回心转意 2024-12-07 10:56:57
using(Dog dog = animal as Dog)
{
    if(dog != null)
    {
        dog.Name;    
        ... 

    }

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

    }

}
寂寞清仓 2024-12-07 10:56:57

我知道我参加聚会的时间太晚了,但我想我应该发布自己的解决方法来解决这个困境,因为我还没有在这里(或任何地方)看到它。

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

重要提示:如果您想通过接口使用 TryAs(),则必须让该接口继承 IAble。

享受!

I know I'm super duper late to the party, but I figured I'd post my own workaround to this dilemma since I haven't seen it on here yet (or anywhere for that matter).

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

With this, you can do things such as:

if (animal.TryAs(out Dog dog))
{
    //Do Dog stuff here because animal is a Dog
}
else
{
    //Cast failed! animal is not a dog
}

IMPORTANT NOTE: If you want to use TryAs() using an Interface, you MUST have that interface inheriting IAble.

Enjoy! ????

甜妞爱困 2024-12-07 10:56:57

有一个解决方法,我给你再举一个例子,你有一个返回字符串 Id 的方法,而不是 if 语句:

var userId = GetUserId();

if (!string.IsNullOrEmpty(userId))
{ 
    //logic
}

你可能需要这样的语法,这是行不通的:

if (string userId = GetUserId() && !string.IsNullOrEmpty(userId))
{
    //logic
}

但是现在,你可以使用以下命令获得相同的结果: :

if (GetUserId() is string userId && !string.IsNullOrEmpty(userId))
{ 
    //logic
}

您的示例中,您当然可以这样做:

if(animal is Dog dog)
{
    //logic
}

但考虑使用方法很有用

var animal = GetAnimal();

if (animal is Dog)
{
    //logic
}

,最后您可以将其重写为:

if(GetAnimal() is Dog dog)
{
    //logic
}

There is workaround, I give you a little bit another example, you have a method which returns string Id, than if statement:

var userId = GetUserId();

if (!string.IsNullOrEmpty(userId))
{ 
    //logic
}

you might be expected syntax like this, which isn't work:

if (string userId = GetUserId() && !string.IsNullOrEmpty(userId))
{
    //logic
}

But now, you can achieve the same result with:

if (GetUserId() is string userId && !string.IsNullOrEmpty(userId))
{ 
    //logic
}

In your example you can do of course:

if(animal is Dog dog)
{
    //logic
}

but it find be usefull to consider using a method

var animal = GetAnimal();

if (animal is Dog)
{
    //logic
}

and finally you can rewrite it to:

if(GetAnimal() is Dog dog)
{
    //logic
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文