问题
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);
回答1:
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.
回答2:
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.
回答3:
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.
回答4:
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.
回答5:
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;
}
回答6:
Did you try
public Guid GetPropertyId(...)
{
return new Guid(Select
.Either(TryToGetTheId(...))
.Or(TrySomethingElseToGetTheId(...))
.Id);
}
回答7:
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.
来源:https://stackoverflow.com/questions/3703555/implicit-conversion-without-assignment