-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
where not condition in generic type constraint #3560
Comments
Generic parameter constraints are not a part of a method signature and cannot be used to overload a method, so this type of solution wouldn't work even if a "not" constraint existed. |
No, I mean that the runtime doesn't allow declaring those two methods because they have identical signatures, which is The appropriate way to handle this today is to declare a single method and have it do a type check: public static void insert<Input>(this Input I)
where Input : IArray
{
if (I is ISrotedArray) {
// handle a sorted array here
}
else {
// handle an unsorted array here
}
} |
@HaloFour can we have something like blow for expression? public InterfaceGroup IOptions:
IOption_1,IOption_2,IOption_3,IOption_4,IOption_5,IOption_6,IOption_7
{ }
public interface IOption_1 { }
public interface IOption_2 { }
public interface IOption_3 { }
public interface IOption_4 { }
public interface IOption_5 { }
public interface IOption_6 { }
public interface IOption_7 { }
public static void OptionDo<Input>(this Input I)
where Input : IOptions
where Input : !IOption2
{
} |
Or alternative of public InterfaceGroup IOptions:
IOption_1,IOption_2,IOption_3,IOption_4,IOption_5,IOption_6,IOption_7
{ }
public interface IOption_1 { }
public interface IOption_2 { }
public interface IOption_3 { }
public interface IOption_4 { }
public interface IOption_5 { }
public interface IOption_6 { }
public interface IOption_7 { }
public Result Put_Option_No5<Input,Result>(this Input I)
where Input : IOption_1, IOption_2, IOption_3, IOption_4, IOption_5, IOption_6, IOption_7
where Result : IOption_1, IOption_2, IOption_3, IOption_4, IOption_6, IOption_7
{
return I;
}
public Result V2_Put_Option_No5<Input, Result>(this Input I)
where Input : IOptions
where Result : IOptions, !IOption5
{
return I;
}
public Result V3_Put_Option_No5<Input, Result>(this Input I)
where Input : IOptions
where Result : IOptions - IOption5
{
return I;
} |
Not without a very compelling use case :) |
As for me, sometimes I want this feature for convert function. Such as convert to string that can take anything but object and string, for example |
@CyrusNajmabadi very compelling use case? :| //Error CS0220 The operation overflows at compile time
int a = int.MaxValue + 1; so why c# get me error in code time? i can get an exception in runtime, but answer is c# trying to stop confusing us and also make debug codes faster, so you can find this error in code time and must get decision right there public static void Add(int i)
{
//no error in code time
int a = int.MaxValue + i;
} sorry about simple samples but you need to very compelling use case and what i talking is very very basic public interface IStream
{
Stream Stream { get; }
}
public interface IReadableStream: IStream { }
public interface IWritableStream: IStream { }
public interface ISeekableStream: IStream { } i recommend something like blow just for better debugging and make clear rule for stop confusing developers public static class StreamEx
{
public static int ReadFrom<StreamType>(
this StreamType IStream,
int Position, byte[] Buffer, int offset, int count)
where StreamType:IReadableStream, ISeekableStream
{
if (IStream.Stream.CanSeek==false)
throw new AccessViolationException("Stream is not Seekable");
IStream.Stream.Seek(Position, SeekOrigin.Begin);
return IStream.Stream.Read(Buffer, offset, count);
}
} so you may ask where is "the not condition" we using, there : public static MS MakeSeekableStream<StreamType>(
this StreamType IStream,
int Position, byte[] Buffer, int offset, int count)
where StreamType: IReadableStream, !ISeekableStream ////<<< there
{
if (IStream.Stream.CanSeek==true)
throw new AccessViolationException("Stream is Seekable");
var MyMs = new MemoryStream();
IStream.Stream.CopyTo(MyMs);
return new MS() { Stream = MyMs };
}
public class MS : IReadableStream, IWritableStream, ISeekableStream
{
public Stream Stream { get; set; }
} so developer can known what is stream type in code time not only at runtime public interface IStream
{
Stream Stream { get; }
}
public interface IReadableStream: IStream { }
public interface IWritableStream: IStream { }
public interface ISeekableStream: IStream { }
public static class StreamEx
{
public static ResultType PutSeekOptionOnlyForCodeTime<StreamType,ResultType>(
this StreamType IStream)
where StreamType: IReadableStream, ISeekableStream
where ResultType: IReadableStream, IWritableStream, ISeekableStream
{
// Error CS0029 Cannot implicitly convert type 'StreamType' to 'ResultType'
return IStream;
}
} i know how can i handle this in c# but what i don't know is how can i put every interface from anonymous types public interface IStream
{
Stream Stream { get; }
}
public interface IReadableStream: IStream { }
public interface IWritableStream: IStream { }
public interface ISeekableStream: IStream { }
public static class StreamEx
{
public static ResultType PutSeekOptionOnlyForCodeTime<StreamType,ResultType>(
this StreamType IStream)
where StreamType: ISeekableStream
where ResultType: AllInterfaces(StreamType) , !ISeekableStream
{
// this just trying to remove one interface, so why always i must make new class for just very simple action?
return IStream;
}
} |
@HaloFour static void Main(string[] args)
{
var value =25;
Action MyAc = () => Console.WriteLine(value); // there made a new hidden private class
} my codes was: public static class Ex
{
public interface ISrotedArray : IArray
{
}
public interface IArray
{
}
public static void insert<Input>(this Input I)
where Input : IArray
{
// Insert At End Of Array
}
//Error CS0111 Type 'Ex' already defines a member called 'insert' with the same parameter types
// V V V
public static void insert<Input>(this Input I)
where Input : IArray,ISrotedArray
{
// Insert At Binary Position Of Array
}
} So compiler can translate to public static class Ex
{
public interface ISrotedArray : IArray
{
}
public interface IArray
{
}
public static void insert<Input>(this Input I)
where Input : IArray
{
if (I is ISrotedArray) {
insert_Type2(I);
}
else {
insert_Type1(I);
}
}
[CompilerGenerated]
private static void insert_Type1<Input>(this Input I)
where Input : IArray
{
// Insert At End Of Array
}
[CompilerGenerated]
private static void insert_Type2<Input>(Input I)
where Input : IArray,ISrotedArray
{
// Insert At Binary Position Of Array
}
} |
Because you're declaring two public functions. The C# compiler does not reinterpret the layout of your classes, it assumes that you know what you're doing. Something similar to this was discussed with overload via pattern matching and that was declined because C# overloading is resolved entirely at compile time whereas this would be runtime resolution. |
Duplicate of #707. |
@Joe4evr i don't talking about overloads, that code isn't implicit and haven't ambiguous method call static class ex1
{
public static void AsSomething<T>(this IEnumerable<IEnumerable<T>> arg) { }
}
static class ex2
{
public static void AsSomething<T>(this IEnumerable<T> arg) {}
}
class Program
{
static void Run<T>(IEnumerable<IEnumerable<T>> IE)
{
IE.AsSomething(); // <<< there is no error such like ambiguous method call
}
} i think that method should be use in same class but i talking about blow public interface ISrotedArray : IArray { }
public interface IArray { }
static class ex1
{
public static void insert<Input>(this Input I)
where Input : IArray
{
// Insert At End Of Array
}
}
static class ex2
{
public static void insert<Input>(this Input I)
where Input : IArray,ISrotedArray
{
// Insert At Binary Position Of Array
}
}
class Program
{
static void Run<T>(ISrotedArray Ar)
{
//Error:The call is ambiguous between the following methods or properties:
//'ex1.insert<Input>(Input)' and 'ex2.insert<Input>(Input)'
Ar.insert(); // <<< ambiguous call Error
}
} |
yes you right but c# also trying to make machine language close to humans logics |
@HaloFour i have idea, i hope that be in Champion "Improved overload candidates" public interface ISrotedArray : IArray { }
public interface IArray { }
static class ex1
{
public static void insert<Input>(this Input I)
where Input : IArray
{
// Insert At End Of Array
}
}
static class ex2
{
public static void insert<Input>(this Input I)
where Input : IArray,ISrotedArray
{
// Insert At Binary Position Of Array
}
}
class Program
{
static void RunAsSorted<T>(ISrotedArray Ar)
{
Ar.insert(); // <<< must select "ex2.insert<Input>"
}
static void RunAsNotSorted<T>(IArray Ar)
{
Ar.insert(); // <<< must select "ex1.insert<Input>"
}
} |
I don't know what that means, but that doesn't sound anything like what C# is trying to do.
Your example is still ambiguous, |
This does seem like a duplicate of #707. Closing as such. |
i don't know what in my examples is understandable in other hand c# have a bug here because
that one can't never select ever as extension method, so why i wrote that and why c# accepted that as extension in same namespace? |
hi can i have "not Condition" in generic types
i mean
The text was updated successfully, but these errors were encountered: