4

保留的问题 - 请参阅底部的编辑
我正在开发一个小型功能库,主要是通过隐藏基本的圈复杂性来提供一些可读性。调用提供者Select<T>(带有一个名为 的辅助工厂Select),用法类似于

public Guid? GetPropertyId(...)
{
    return Select
        .Either(TryToGetTheId(...))
        .Or(TrySomethingElseToGetTheId(...))
        .Or(IGuessWeCanTryThisTooIfWeReallyHaveTo(...))
        //etc.
        ;
}

并且库会处理短路等问题。我还添加了一个隐式转换 from Select<T>to 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);
4

7 回答 7

5

虽然隐式转换确实在这里不起作用,但通过ValueSelect<T>. 那么你的表达将是Select.[operations].Value.Id,它仍然读起来相当不错。

于 2010-09-13T19:41:22.157 回答
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。

于 2010-09-14T16:02:36.527 回答
2

我认为这是不可行的。某种操作员必须发挥作用才能导致铸造。编译器/运行时不能只是“知道”您希望它是 T 类型,您必须以某种方式指示它这样做。

于 2010-09-13T19:15:22.927 回答
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 中更好地阅读。

于 2010-09-13T19:25:17.353 回答
1

我想我看到了你的问题。Or返回 a Select,而不是 a ServiceResult,因此编译器无法知道您希望IdServiceResult对象中获取属性。怎么可能?它是否应该看到没有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; 
}
于 2010-09-13T20:33:29.890 回答
0

你试过了吗

public Guid GetPropertyId(...)
{
    return new Guid(Select
        .Either(TryToGetTheId(...))
        .Or(TrySomethingElseToGetTheId(...))
        .Id);
}
于 2010-09-13T19:12:30.130 回答
0

如果您只打算处理特定类型,则可以添加包装方法或属性。如果 myThing 有一个返回“self.internalThing.Bar”的“Bar”类型的方法,那么人们可以保持这样的错觉,即返回 myThing 的表达式实际上是在返回其包装类型的表达式。但是,我知道在一般情况下无法做到这一点。对于未来的 C# 和 VB 版本,允许“包装”类中的一个属性可能很有用,但我不知道在存在的语言中没有办法做到这一点。

于 2010-09-13T19:47:59.243 回答