没有赋值的隐式转换?

时间:2010-09-13 19:06:13

标签: c# casting implicit

保留问题 - 请参阅底部的修改
我正在研究一个小型函数库,主要是通过隐藏基本的圈复杂度来提供一些可读性。提供程序名为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);

7 个答案:

答案 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版本来说,允许类中的一个属性被“包装”可能是有用的,但我知道在语言中没有办法实现它。