没有赋值的隐式转换?

发布于 2024-09-18 19:01:10 字数 1470 浏览 5 评论 0原文

保留问题 - 请参阅底部的编辑
我正在开发一个小型函数库,基本上是通过隐藏基本的圈复杂度来提供一些可读性。该提供程序称为 Select (带有一个名为 Select 的帮助器工厂),用法类似于

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

,库将处理短路等问题。还添加了从 SelectT 的隐式转换,因此我可以编写

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);

Preserved question - see Edit at the bottom
I'm working on a small functional library, basically to provide some readability by hiding basic cyclomatic complexities. The provider is called Select<T> (with a helper factory called Select), and usage is similar to

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

and the library will take care of the short circuiting, etc. I also added an implicit conversion from Select<T> to T, so I can write

public Guid GetPropertyId(...)
{
    ServiceResult result = Select
        .Either(TryToGetTheId(...))
        .Or(TrySomethingElseToGetTheId(...));

    return result.Id;
}

What I'd really like to be able to do is an implicit conversion to T without assignment:

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;
}

However, the specified syntax doesn't work - I have to either assign it to a variable, or explicitly cast it. Is there a way to get an implicit cast inline?

EDIT

What I want to do is this:

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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

晚雾 2024-09-25 19:01:32

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

If you are only going to be dealing with specific types, you could add wrapper methods or properties. If myThing has a method of type "Bar" which returns "self.internalThing.Bar", then one could maintain the illusion that that an expression returning a myThing was really returning an expression of its wrapped type. I know of no way to do that in the general case, however. It might be useful for future C# and VB versions to allow one property in a class to be "wrapped", but I know of no way to do that in the language as it exists.

も让我眼熟你 2024-09-25 19:01:30

你尝试过吗

public Guid GetPropertyId(...)
{
    return new Guid(Select
        .Either(TryToGetTheId(...))
        .Or(TrySomethingElseToGetTheId(...))
        .Id);
}

Did you try

public Guid GetPropertyId(...)
{
    return new Guid(Select
        .Either(TryToGetTheId(...))
        .Or(TrySomethingElseToGetTheId(...))
        .Id);
}
骑趴 2024-09-25 19:01:28

我想我看到了你的问题。 Or 返回 Select,而不是 ServiceResult,因此编译器无法知道您期望获取 Id<来自 ServiceResult 对象的 /code> 属性。怎么可能呢?它是否应该看到没有 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; 
}

I think I see your problem. Or returns a Select, not a ServiceResult, so there's no way that the compiler could know that you expect to get the Id property from a ServiceResult object. How could it? Should it see that there is no Select.Id property and start looking for possible implicit conversions to see if one of them has a property called Id?

Here are a few of your choices:

public Guid GetPropertyId(...) 
{ 
    return  ((ServiceResult)
        Select 
        .Either(TryToGetTheId(...)) 
        .Or(TrySomethingElseToGetTheId(...)))
        .Id; 
} 

or

class Select
{
    public ServiceResult AsServiceResult()
    {
        return (ServiceResult)this;
    }
}

public Guid GetPropertyId(...) 
{ 
    return  
        Select 
        .Either(TryToGetTheId(...)) 
        .Or(TrySomethingElseToGetTheId(...)) 
        .AsServiceResult()
        .Id; 
} 

or

class Select
{
    public Guid Id { get { return ((ServiceResult)this).Id; } }
}

public Guid GetPropertyId(...) 
{ 
    return  
        Select 
        .Either(TryToGetTheId(...)) 
        .Or(TrySomethingElseToGetTheId(...)) 
        .Id; 
}
野味少女 2024-09-25 19:01:25

如果你想将转换为 guid 内联,你可以做一个扩展方法,

public static Guid ToGuid(this string id)
{
    return new Guid(id);
}

public Guid GetPropertyId(...)
{
    return Select
        .Either(TryToGetTheId(...))
        .Or(TrySomethingElseToGetTheId(...))
        .Id
        .ToGuid();
}

我认为它并没有真正添加一些东西,但在我的观点中更好读。

If you want put the conversion to guid inline you can do a extension method

public static Guid ToGuid(this string id)
{
    return new Guid(id);
}

public Guid GetPropertyId(...)
{
    return Select
        .Either(TryToGetTheId(...))
        .Or(TrySomethingElseToGetTheId(...))
        .Id
        .ToGuid();
}

i don't think it really add something, but in my pov is better to read.

亽野灬性zι浪 2024-09-25 19:01:23

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

I don't think that is doable; some kind of operator has to come into play to cause the casting. The compiler/runtime can't just 'know' that you want it to be of type T, you have to somehow instruct it to do so.

稚然 2024-09-25 19:01:21

我的问题是:当使用成员访问(“点”)运算符时,有没有办法告诉编译器查找 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。

My question is: when using the member access ("dot") operator, is there a way to tell the compiler to look up both the members of Bar and a type to which Bar is implicitly convertible?

Yes, there are two ways to do that.

The first is called "inheritance". You do it like this:

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.

That tells the compiler "when you're looking up members of Bar, look up members of Blah too". It also tells the compiler that instances of Bar are implicitly convertible to type Blah.

Blah can be either a class or an interface type.

The second is called "class and interface constraints on type parameters". You hint to the compiler like this:

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

Now t is implicitly convertible to Blah, and member access on t will include members declared on Blah.

Again, Blah can be an interface or class type.

There are no other ways in C# to affect member lookup on a type Bar such that the added members are declared on a type Blah, where Bar is implicitly convertible to Blah.

So尛奶瓶 2024-09-25 19:01:19

虽然隐式转换确实在这里不起作用,但通过向 Select 添加 Value 属性,您可能会比显式转换做得更好。那么您的表达式将是 Select.[operations].Value.Id,读起来仍然相当不错。

While it's true that an implicit cast won't work here, you could possibly do better than an explicit cast by adding a Value property to Select<T>. Then your expression would be Select.[operations].Value.Id, which still reads reasonably well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文