保留问题 - 请参阅底部的修改
我正在研究一个小型函数库,主要是通过隐藏基本的圈复杂度来提供一些可读性。提供程序名为Select<T>
(有一个名为Select
的帮助程序工厂),用法类似于
public Guid? GetPropertyId(...)
{
return Select
.Either(TryToGetTheId(...))
.Or(TrySomethingElseToGetTheId(...))
.Or(IGuessWeCanTryThisTooIfWeReallyHaveTo(...))
//etc.
;
}
并且库会处理短路等问题。我还添加了从Select<T>
到T
的隐式转换,所以我可以写
public Guid GetPropertyId(...)
{
ServiceResult result = Select
.Either(TryToGetTheId(...))
.Or(TrySomethingElseToGetTheId(...));
return result.Id;
}
我真正希望能够做的是在没有赋值的情况下隐式转换为T:
public Guid GetPropertyId(...)
{
return
//This is the part that I want to be implicitly cast to a ServiceResult
Select
.Either(TryToGetTheId(...))
.Or(TrySomethingElseToGetTheId(...))
//Then I want to access this property on the result of the cast
.Id;
}
但是,指定的语法不起作用 - 我必须将其分配给变量,或者显式地转换它。有没有办法获得内联隐式转换?
修改
我想做的是:
class Foo {
public int Fuh { get; set; }
}
class Bar {
private Foo _foo;
public static implicit operator Foo (Bar bar)
{
return bar._foo;
}
}
//What I have to do
Foo bar = GetABar();
DoSomethingWith(bar.Fuh);
//What I want to do
DoSomethingWith(GetABar().Fuh);
答案 0 :(得分:5)
虽然隐式转换在这里不起作用,但通过向Value
添加Select<T>
属性,您可能比明确转换更好。那么你的表达式将是Select.[operations].Value.Id
,它仍然可以很好地读取。
答案 1 :(得分:5)
我的问题是:当使用成员访问(“点”)运算符时,有没有办法告诉编译器查找Bar的成员和Bar可以隐式转换的类型?
是的,有两种方法可以做到这一点。
第一种称为“继承”。你这样做:
class Bar : Blah { ... }
...
Bar bar = new Bar();
bar.Whatever(); // member access will look up members of both Bar and Blah.
Blah blah = bar; // bar is implicitly convertible to Blah.
告诉编译器“当你查找Bar的成员时,也要查找Blah的成员”。它还告诉编译器Bar的实例可以隐式转换为Blah类型。
Blah可以是类或接口类型。
第二个称为“类型参数的类和接口约束”。你像这样提示编译器:
void M<T>(T t) where T : Blah
{
t.Whatever(); // member access looks up members of Blah on t
Blah blah = t; // t is implicitly convertible to Blah
现在t可以隐式转换为Blah,而t上的成员访问将包括在Blah上声明的成员。
同样,Blah可以是接口或类类型。
C#中没有其他方法可以影响类型Bar上的成员查找,以便在Blah类型上声明添加的成员,其中Bar可以隐式转换为Blah。
答案 2 :(得分:2)
我认为这不可行;某种操作员必须发挥作用才能引起铸造。编译器/运行时不能只“知道”你希望它是T类型,你必须以某种方式指示它这样做。
答案 3 :(得分:1)
如果您想将转换内联到guid,可以执行扩展方法
public static Guid ToGuid(this string id)
{
return new Guid(id);
}
public Guid GetPropertyId(...)
{
return Select
.Either(TryToGetTheId(...))
.Or(TrySomethingElseToGetTheId(...))
.Id
.ToGuid();
}
我认为它确实没有添加任何东西,但在我的pov中更好阅读。
答案 4 :(得分:1)
我想我看到了你的问题。 Or
返回Select
,而不是ServiceResult
,因此编译器无法知道您希望从Id
对象获取ServiceResult
属性。怎么可能呢?是否应该看到没有Select.Id
属性并开始寻找可能的隐式转换,以查看其中一个是否具有名为Id
的属性?
以下是您的一些选择:
public Guid GetPropertyId(...)
{
return ((ServiceResult)
Select
.Either(TryToGetTheId(...))
.Or(TrySomethingElseToGetTheId(...)))
.Id;
}
或
class Select
{
public ServiceResult AsServiceResult()
{
return (ServiceResult)this;
}
}
public Guid GetPropertyId(...)
{
return
Select
.Either(TryToGetTheId(...))
.Or(TrySomethingElseToGetTheId(...))
.AsServiceResult()
.Id;
}
或
class Select
{
public Guid Id { get { return ((ServiceResult)this).Id; } }
}
public Guid GetPropertyId(...)
{
return
Select
.Either(TryToGetTheId(...))
.Or(TrySomethingElseToGetTheId(...))
.Id;
}
答案 5 :(得分:0)
你试过吗
public Guid GetPropertyId(...)
{
return new Guid(Select
.Either(TryToGetTheId(...))
.Or(TrySomethingElseToGetTheId(...))
.Id);
}
答案 6 :(得分:0)
如果您只打算处理特定类型,则可以添加包装器方法或属性。如果myThing有一个类型为“Bar”的方法,它返回“self.internalThing.Bar”,那么可以保持一个假设,即返回myThing的表达式实际上正在返回其包装类型的表达式。但是,我知道在一般情况下无法做到这一点。对于未来的C#和VB版本来说,允许类中的一个属性被“包装”可能是有用的,但我知道在语言中没有办法实现它。