C# 可从或作为识别?
我有下一个代码:C# 可从或作为识别?,c#,generics,inheritance,interface,C#,Generics,Inheritance,Interface,我有下一个代码: private T CreateInstance<T>(object obj) // where T : ISomeInterface, class { ... if (!typeof(T).IsAssignableFrom(obj.GetType())) { throw ..; } return (T)obj; } 如果没有-为什么?如果(!(条为T)){throw.;} 或者,如果您不需要自己的异常消息,最简单的答案就是: retu
private T CreateInstance<T>(object obj) // where T : ISomeInterface, class
{
...
if (!typeof(T).IsAssignableFrom(obj.GetType())) { throw ..; }
return (T)obj;
}
如果没有-为什么?如果(!(条为T)){throw.;}
或者,如果您不需要自己的异常消息,最简单的答案就是:
return (T)obj;
如果它不可强制转换,则会抛出InvalidCastException并忽略返回。除非您添加了更多的逻辑或自定义错误消息,否则无需进行检查并抛出您自己的异常。甚至更好,因为它更容易读取真正的条件
if(obj is T){
//Create instance.
}
else{
throw new InvalidArgumentException("Try Again");
}
看
第二个是安全的…因为在第一个中,如果obj为null,您将得到异常(obj.GetType()-->NullReferenceException)
当你把“是”和“是”放在一起时,原因可能是这样的(括号越少,可读性越好)
已编辑
通过减少括号的数量,我最初的意思是反向检查:即
if (obj is T)
而不是
if (!(obj is T))
所以最终版本可以是
if (obj is T)
{
return (T)obj;
}
throw new ...
或
class约束
,其中T:class
允许您将用作T
语句
private T CreateInstance<T>(object obj) where T : class
{
if (!(obj is T)) { throw new ArgumentException("..."); }
return obj as T;
}
private T CreateInstance(object obj),其中T:class
{
如果(!(obj是T)){抛出新的ArgumentException(“…”);}
将obj返回为T;
}
或
private T CreateInstance(对象obj)
{
如果(!(obj是T)){抛出新的ArgumentException(“…”);}
返回(T)obj;
}
另一种变体:
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;
}
private T CreateInstance(object obj),其中T:isome接口//如上所述
{
...
T结果=obj作为T;
如果(结果==null)
{扔..;}
其他的
返回结果;
}
它可能用于处理转换构造函数允许该操作的情况,但显然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时,obj.GetType()将引发null引用异常,而不是引发指定的异常
编辑:我现在看到,如果T可以是值类型,那么您的代码版本将不会编译,但是其他建议的解决方案,如“if(obj是T)return(T)obj;”将编译。因此,我明白为什么您建议的替代方案不起作用,但我不明白为什么您不能使用“is”。是的,只要t是引用类型或可为null,您可以在那里使用
作为
运算符代码,而不是原始代码
as
是推荐的C#铸造方法(见比尔·瓦格纳的《有效C#》第3项)
发件人:
如果c和当前类型表示相同的类型,或者如果当前类型在c的继承层次结构中,或者如果当前类型是c实现的接口,或者如果c是泛型类型参数且当前类型表示c的一个约束,则[返回]true。如果这些条件都不为真,或者如果c为null,则为false
根据C规范第7.10.11节:
在形式为E as T的操作中,E必须是表达式,T必须是引用类型、已知为引用类型的类型参数或可为null的类型
因此,您可以看到它们进行了类似的检查。您可能正在查找
is
关键字,语法为表达式is type
将其描述为执行所需的检查:
is表达式的计算结果为true,如果
以下两种情况均适用
会议:
•表达式不为空
•表达
可以转换为类型。就是演员阵容
形式的表达
(类型)(表达式)将完成
没有抛出异常
编辑
然而,如果在你尝试之前不只是确定你是否可以投下一些东西,as关键字可能是你在文章中描述的最好的解决方案
下面的代码将执行相同的功能
try
{
T result = (T)obj;
return result;
}
catch (InvalidCastException ex)
{
// throw your own exception or deal with it in some other way.
}
您喜欢哪种方法取决于您……此场景使用的是可识别的:
foreach (PropertyInfo property in GetType().GetProperties())
{
if (typeof(SubPresenter).IsAssignableFrom(property.PropertyType))
{//Do Sth.}
}
只针对喜欢玩数字游戏的开发者(谁不喜欢!) 在下面,您会发现的性能比较测试可从与As中识别。当然,只有当您有一个实例时,这才算 测试结果(一百万次尝试): IsAssignableFrom:经过146毫秒
[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);
}
A操作员:运行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);
}
[TestMethod]
public void可从VSAsperformanceTest()中签名
{
秒表秒表=新秒表();
秒表。开始();
int尝试次数=1000000次;
string value=“这是一个测试”;
for(int-trunt=0;trunt
酒吧是从哪里来的?你修复了。。。您将bar作为T…如果您无论如何都要抛出,为什么不直接return(T)obj
@Anton:我只会在obj为T的情况下返回,否则我会抛出一个例外你已经参与了同样的讨论:)我想他可能需要添加一些约束,但这不是他想要实现的吗?如果T可以是这种类型。。。铸造它?可惜它无法编译。你试过这个吗?为什么你不想在施放之前检查类型?@Daniel:没有类它是不可编译的constraint@Daniel戴森:当然不,“扔…”是C#不允许的compiler@Orsol,原始答案没有类约束(其中t:…)。我可以在我的cod中添加一个新的异常(“”)
try
{
T result = (T)obj;
return result;
}
catch (InvalidCastException ex)
{
// throw your own exception or deal with it in some other way.
}
foreach (PropertyInfo property in GetType().GetProperties())
{
if (typeof(SubPresenter).IsAssignableFrom(property.PropertyType))
{//Do Sth.}
}
[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);
}