代码之家  ›  专栏  ›  技术社区  ›  abatishchev Karl Johan

是从还是作为?

  •  5
  • abatishchev Karl Johan  · 技术社区  · 14 年前

    我有下一个代码:

    private T CreateInstance<T>(object obj) // where T : ISomeInterface, class
    {
        ...
    
        if (!typeof(T).IsAssignableFrom(obj.GetType())) { throw ..; }
    
        return (T)obj;
    }
    

    T result = obj as T;
    
    if (result == null) { throw ..; }
    
    return result;
    

    如果不是-为什么?

    11 回复  |  直到 14 年前
        1
  •  4
  •   abatishchev Karl Johan    14 年前

    另一种变体:

    private T CreateInstance<T>(object obj) where T : ISomeInterface // as OP mentioned above
    {
        ...
    
        T result = obj as T;
        if (result == null)
            { throw ..; }
        else 
           return result;
    }
    
        2
  •  6
  •   Davy8    14 年前

    那怎么办 if (!(bar is T)) { throw ..; }

    或者,如果您不需要自己的异常消息,最简单的答案就是:

    return (T)obj;
    

        3
  •  3
  •   Matt Ellen Bipin Vayalu    14 年前

    是的,你可以用你的 as

    作为 是C#铸造的推荐方法(见比尔·瓦格纳的有效C#第3项)

    system.type.isassignablefrom :

    根据C规范第7.10.11节:

    在形式为E as T的操作中,E必须是表达式,T必须是引用类型、已知为引用类型的类型参数或可为null的类型

    所以你可以看到他们做了类似的检查。

        4
  •  2
  •   desco    14 年前

    可能是这样(括号越少,可读性越好)

    if (obj is T)
    {
        return (T)obj;
    }
    else
       throw new ...
    

    编辑

    if (obj is T)
    

    而不是

    if (!(obj is T))
    

    所以最终版本可以

    if (obj is T)
    {
        return (T)obj;
    }
    
    throw new ...
    

    if (obj is T)
    {
        return (T)obj;
    }
    else
    {
       throw new ...
    }
    
        5
  •  1
  •   Community CDub    7 年前

    看到了吗 this post

    当你把“是”和“因为”放在一起 performance issues..

        6
  •  1
  •   Daniel Dyson    14 年前

    where T : class 允许您使用 as T

    private T CreateInstance<T>(object obj) where T : class
    {
        if (!(obj is T)) { throw new ArgumentException("..."); }
        return obj as T;
    }
    

    private T CreateInstance<T>(object obj)
    {
        if (!(obj is T)) { throw new ArgumentException("..."); }
        return (T)obj;
    }
    
        7
  •  1
  •   Fiona - myaccessible.website    14 年前

    你可能在找 is 关键字,语法为 expression is type

    Documentation

    以下两种情况都适用 遇见:

    表达 形式的表达 不会引发异常。

    编辑 然而,如果不是在尝试之前就确定是否可以强制转换某些内容,那么as关键字可能是您在帖子中描述的最佳解决方案。

    下面的代码将执行相同的功能。。。

    try
    {
        T result = (T)obj;
        return result;
    }
    catch (InvalidCastException ex)
    {
         // throw your own exception or deal with it in some other way.
    }
    

        8
  •  1
  •   IvanYu    12 年前

    此场景使用的IsAssignableFrom:

    foreach (PropertyInfo property in GetType().GetProperties())
    {
        if (typeof(SubPresenter).IsAssignableFrom(property.PropertyType))
        {//Do Sth.}
    }
    
        9
  •  1
  •   Roel van Megen    10 年前

    只针对那些喜欢玩数字游戏的开发人员(他们不喜欢!)。

    IsAssignableFrom公司 与。 作为

    测试结果(一百万次尝试):

    ISassignable来自:

    经过7毫秒

    [TestMethod]
    public void IsAssignableFromVsAsPerformanceTest()
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
    
        int attempts = 1000000;
        string value = "This is a test";
    
        for (int attempt = 0; attempt < attempts; attempt++) {
            bool isConvertible = typeof(IConvertible).IsAssignableFrom(value.GetType());
        }
    
        stopwatch.Stop();
        Console.WriteLine("IsAssignableFrom: {0} ms elapsed", stopwatch.ElapsedMilliseconds);
    
        stopwatch.Restart();
    
        for (int attempt = 0; attempt < attempts; attempt++) {
            bool isConvertible = value as string != null;
        }
    
        stopwatch.Stop();
        Console.WriteLine("AsOperator: {0} ms elapsed", stopwatch.ElapsedMilliseconds);
    }
    
        10
  •  -2
  •   BlueMonkMN    14 年前

    它可能是用来处理转换构造函数允许该操作的情况,但显然IsAssignableFrom也不能处理这种情况。没有看到任何 可以

    class Program
    {
      static void Main(string[] args)
      {
         B bValue = new B(123);
         Console.WriteLine(typeof(A).IsAssignableFrom(bValue.GetType()));
         //Console.WriteLine(bValue is A);
         //Console.WriteLine(bValue as A == null);
         A aValue = bValue;
         Console.WriteLine(aValue.ToString());
      }
    }
    
    class A
    {
      string value;
      public A(string value)
      {
         this.value = value;
      }
      public override string ToString()
      {
         return value;
      }
    }
    
    class B
    {
      int value;
    
      public B(int value)
      {
         this.value = value;
      }
    
      public static implicit operator A(B value)
      {
         return new A(value.value.ToString());
      }
    }
    

    最后,我不明白为什么你不想使用你的代码版本,除非你 希望 当obj为null时引发异常的代码。这是我能看到的唯一区别。当obj为null时,GetType()将引发null引用异常,而不是引发指定的异常。

    编辑: 我现在看到,如果T可以是值类型,那么您的代码版本将不会编译,但是建议的另一种解决方案是“if(obj is T)return(T)obj;”将编译。所以我明白为什么你建议的替代方案不起作用,但我不明白为什么你不能使用“是”。

        11
  •  -3
  •   Nix    14 年前

    或者更好,因为它更容易阅读真正的条件句。

     if(obj is T){
        //Create instance. 
     }
     else{
        throw new InvalidArgumentException("Try Again");
     }