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
}
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)
{
// ...
}
下面是一些额外的脏代码(不像 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();
}
}
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 (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;
}
/// <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
}
这是因为 if 语句中的 像狗一样的动物产生的结果与:
animal is Dog ? (Dog)(animal) : (Dog)null
然后 不是无效的部分检查上述语句的结果是否为空。只有当该语句为 true 时,才会创建 Dog Dog 类型的变量,该变量不能为 null。