Gre*_*ech 7 c# f# casting guard-clause
我的情况是我的很多类都是众所周知但不同类型的无序对象的容器,例如容器可能如下所示:
public class Container
{
public A A { get; private set; }
public B B { get; private set; }
public C C { get; private set; }
public bool StoreIfKnown(object o)
{
// TODO...
}
}
Run Code Online (Sandbox Code Playgroud)
所以,如果o
是类型A
应当存储在A
属性类型B
的B
物业等.
在F#中,StoreIfKnown
方法可以写成如下所示(原因是语法错误,我的F#不是很好而且非常生疏):
match o with
| ?: A a -> A <- a; true
| ?: B b -> B <- b; true
| ?: C c -> C <- c; true
| _ -> false
Run Code Online (Sandbox Code Playgroud)
但在C#中,唯一的方法似乎是相当冗长:
if (o is A)
{
this.A = (A)o;
return true;
}
if (o is B)
{
this.B = (B)o;
return true;
}
// etc.
return false;
Run Code Online (Sandbox Code Playgroud)
我可以使用as
关键字来避免测试/转换模式更快,但更加冗长.
在C#中有没有优雅的方法呢?
Bri*_*ian 11
您可以在'o'和helper类上创建一个扩展方法来启用编程模型
o.Match<A>( a => { this.A = a; return true; } )
.Match<B>( b => { this.B = b; return true; } )
.Else( () => { return false; } )
Run Code Online (Sandbox Code Playgroud)
但要注意在这里做太多类似DSL的hackery,以免你最终得到一个只有你理解的API.
也可以看看
它不像Brian的解决方案那样漂亮,但这并不需要定义新的DSL.你会注意到你重复以下代码:
if (o is {DataType})
{
{Property} = ({DataType})o;
return true;
}
Run Code Online (Sandbox Code Playgroud)
它很容易将该模板拉入自己的方法,结果如下:
public class Container
{
public A A { get; private set; }
public B B { get; private set; }
public C C { get; private set; }
private bool TestProp<T>(object o, Action<T> f)
{
if (o is T)
return false;
f((T)o);
return true;
}
public bool StoreIfKnown(object o)
{
return
TestProp<A>(o, x => A = x) ||
TestProp<B>(o, x => B = x) ||
TestProp<C>(o, x => C = x) ||
false;
}
}
Run Code Online (Sandbox Code Playgroud)
如果您正在使用引用类型,则可以通过以下调整来利用类型推断:
private bool TestProp<T>(T o, Action<T> f)
{
if (o == null)
return false;
f(o);
return true;
}
public bool StoreIfKnown(object o)
{
return
TestProp(o as A, x => A = x) ||
TestProp(o as B, x => B = x) ||
TestProp(o as C, x => C = x) ||
false;
}
Run Code Online (Sandbox Code Playgroud)
我一直在玩一个小小的匹配器(灵感来自Brian的答案),它允许类型检查,保护条款,以及从整个事物中返回结果.它使用类型推断,因此您需要指定类型的唯一位置是您真正想要的位置.
因此,想象类型C
具有IsActive
我们想要的属性true
,它看起来像这样:
var stored = Match.Against(o)
.When<A>().Then(a => { this.A = a; return true; })
.When<B>().Then(b => { this.B = b; return true; })
.When<C>(c => c.IsActive).Then(c => { this.C = c; return true; })
.Otherwise(a => false);
Run Code Online (Sandbox Code Playgroud)
我认为这是非常可读的,特别是因为它允许在实际匹配之前对派生类型运行谓词,这是我需要的.
代码非常冗长,因为它在后台需要一些部分指定的构建器类来允许类型推断工作,所以我不能在这里发布它.但是,如果有人感兴趣,请在评论中告诉我,我会将其粘贴在我的博客上,并在此处添加链接.